@clien-ai/mcp 0.1.2 → 0.1.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.
@@ -0,0 +1,334 @@
1
+ /**
2
+ * `clien_research_status` — recovery + polling tool for an in-flight or
3
+ * already-finished research job.
4
+ *
5
+ * Why this exists: `clien_research` is a 15-25 minute synchronous tool call.
6
+ * If the MCP stdio pipe breaks midway (host read-timeout, network hiccup),
7
+ * the caller gets `MCP error -32000: Connection closed` while the backend
8
+ * job carries on and eventually writes a complete report. Without this
9
+ * tool, the host AI has no way to learn what happened to the in-flight
10
+ * job — its only option is to call `clien_research` again, which spawns a
11
+ * fresh job and debits another 5 credits. The user pays twice for one
12
+ * outcome.
13
+ *
14
+ * Contract:
15
+ * 1. Ensure a valid bearer token (uses the same session cache as
16
+ * `clien_research` — no extra OAuth dance on second/third calls).
17
+ * 2. GET /api/validate/{job_id}/events?since=0&limit=50 — small payload
18
+ * that carries the current `job.status`, `job.done`, latest events,
19
+ * and totalCostCents. Reuses the bearer-auth endpoint already used
20
+ * by `runResearch`'s polling loop.
21
+ * 3. If `job.done` is true AND status is 'complete':
22
+ * GET /api/validate/{job_id}/report and return the full markdown +
23
+ * structured `_meta.report_data` (same shape as a fresh
24
+ * `clien_research` success).
25
+ * 4. If `job.done` is true AND status is 'failed' / 'cancelled':
26
+ * return a short text summary + `_meta.status` so the host AI can
27
+ * surface the failure to the user.
28
+ * 5. If the job is still running, return a brief text summary
29
+ * ("Still researching — last activity: …") + the latest event so
30
+ * the host AI can choose to wait and call again, or give up.
31
+ *
32
+ * Error mapping mirrors `clien_research`: 404 → "job not found", 401 →
33
+ * "session expired, re-run clien_research to re-authenticate" (the
34
+ * cached session is invalidated so the next tool call rebuilds from
35
+ * disk). Network errors / 5xx surface raw because the caller can just
36
+ * retry — this tool is read-only, no work is lost.
37
+ */
38
+ import { z } from 'zod';
39
+ import { ResearchReportDataSchema } from '../types/report.js';
40
+ import { ToolError } from './errors.js';
41
+ import { apiCall, categorizeFetchError, truncate, webJobUrl, } from './research.js';
42
+ const EVENTS_FETCH_TIMEOUT_MS = 30_000;
43
+ const REPORT_FETCH_TIMEOUT_MS = 60_000;
44
+ const LIST_FETCH_TIMEOUT_MS = 30_000;
45
+ /** How many recent runs to pull when recovering without a job_id. */
46
+ const LIST_LIMIT = 20;
47
+ /** Max chars of a run's prompt to surface in a disambiguation list. */
48
+ const IDEA_SNIPPET_MAX = 120;
49
+ /** Non-terminal statuses — a run in one of these is still in flight. */
50
+ const ACTIVE_STATUSES = new Set(['initialising', 'researching', 'synthesising']);
51
+ export const StatusInputSchema = z.object({
52
+ job_id: z
53
+ .string()
54
+ .uuid()
55
+ .optional()
56
+ .describe('UUID of the research job to query. Returned in the `_meta.job_id` ' +
57
+ 'field of a prior `clien_research` call, surfaced in error ' +
58
+ 'messages when a run dropped mid-flight (e.g. "MCP error -32000"), ' +
59
+ 'and printed to the MCP server\'s stderr log as ' +
60
+ '`[clien-mcp] research started job_id=<uuid>` at run start. Use ' +
61
+ 'this tool to RECOVER an in-flight job instead of calling ' +
62
+ '`clien_research` again — calling research again would spawn a ' +
63
+ 'new run and debit another 5 credits for the same outcome. ' +
64
+ 'OPTIONAL: omit it entirely to recover a run whose job_id was lost ' +
65
+ 'in a -32000 drop — the tool then finds your recent run(s). If it ' +
66
+ 'returns several, re-call with the `job_id` whose idea matches the ' +
67
+ 'one you were researching.'),
68
+ });
69
+ export class StatusToolError extends ToolError {
70
+ }
71
+ const TERMINAL_STATUSES = new Set(['complete', 'failed', 'cancelled']);
72
+ export async function getResearchStatus(input, deps) {
73
+ // A no-argument tool call arrives as `undefined` (or `{}`); coerce so the
74
+ // object schema validates and the omitted-job_id recovery path can run.
75
+ const parsed = StatusInputSchema.safeParse(input ?? {});
76
+ if (!parsed.success) {
77
+ const details = parsed.error.issues
78
+ .map((i) => `${i.path.join('.') || 'input'}: ${i.message}`)
79
+ .join('; ');
80
+ throw new StatusToolError(`Invalid input — ${details}`);
81
+ }
82
+ const fetchImpl = deps.fetch ?? fetch;
83
+ const ctx = {
84
+ config: deps.config,
85
+ session: deps.session,
86
+ fetch: fetchImpl,
87
+ };
88
+ // Recovery-without-id: no job_id supplied → discover the caller's run(s).
89
+ // Either resolve to a single job (and fall through to the normal
90
+ // events→report path) or return a disambiguation list directly.
91
+ let jobId = parsed.data.job_id;
92
+ if (!jobId) {
93
+ const resolution = await resolveJobId(ctx, deps);
94
+ if (resolution.kind === 'disambiguate')
95
+ return resolution.result;
96
+ jobId = resolution.jobId;
97
+ }
98
+ // 1. Fetch the current state via the events endpoint. since=0&limit=50
99
+ // means we always get the most recent batch (the backend orders ascending
100
+ // by sequence_number and limits to the first `limit`; sequence_number = 1
101
+ // is the oldest, so this gives the FIRST 50, not the most recent 50.
102
+ // That's the desired behavior for first-time callers — they get the full
103
+ // context, not a tail-only view. Hosts wanting incremental polls can call
104
+ // this tool again with the same job_id; we surface last_sequence in
105
+ // _meta so callers can manage their own paging if they want.
106
+ let eventsResponse;
107
+ try {
108
+ eventsResponse = await apiCall(ctx, 'GET', `/api/validate/${jobId}/events?since=0&limit=50`, {
109
+ timeoutMs: EVENTS_FETCH_TIMEOUT_MS,
110
+ });
111
+ }
112
+ catch (err) {
113
+ const e = err;
114
+ if (e.name === 'AbortError' || e.name === 'TimeoutError') {
115
+ throw new StatusToolError(`Status fetch timed out after ${EVENTS_FETCH_TIMEOUT_MS / 1000}s. Try again in a moment.`, { jobId });
116
+ }
117
+ throw err;
118
+ }
119
+ if (!eventsResponse.ok) {
120
+ const category = categorizeFetchError(eventsResponse.status);
121
+ if (category === 'auth') {
122
+ if (eventsResponse.refreshError?.kind !== 'transient') {
123
+ // Genuine auth failure — drop the cached session so the next tool
124
+ // call (likely a fresh clien_research) rebuilds from disk.
125
+ deps.invalidateSession?.();
126
+ }
127
+ throw new StatusToolError(`Session expired. Re-run clien_research to re-authenticate; the job is unaffected and can also be viewed at ${webJobUrl(deps.config, jobId)}.`, { jobId });
128
+ }
129
+ if (eventsResponse.status === 404) {
130
+ throw new StatusToolError(`No research job found with id ${jobId}. The id may belong to a different account, may be malformed, or may never have existed.`, { jobId });
131
+ }
132
+ const text = await eventsResponse.text().catch(() => '');
133
+ throw new StatusToolError(`Failed to fetch status (HTTP ${eventsResponse.status}): ${truncate(text, 200)}`, { jobId });
134
+ }
135
+ const eventsJson = (await eventsResponse.json().catch(() => null));
136
+ const status = eventsJson?.job?.status ?? 'unknown';
137
+ const done = eventsJson?.job?.done === true || TERMINAL_STATUSES.has(status);
138
+ const totalCostCents = typeof eventsJson?.job?.totalCostCents === 'number'
139
+ ? eventsJson.job.totalCostCents
140
+ : undefined;
141
+ const lastSequence = typeof eventsJson?.lastSequence === 'number'
142
+ ? eventsJson.lastSequence
143
+ : undefined;
144
+ // 2. Terminal-complete path: fetch the full report (same shape as
145
+ // runResearch's success return) so a caller can present the report to
146
+ // the user without any second tool call.
147
+ if (status === 'complete') {
148
+ let reportResponse;
149
+ try {
150
+ reportResponse = await apiCall(ctx, 'GET', `/api/validate/${jobId}/report`, {
151
+ acceptJson: true,
152
+ timeoutMs: REPORT_FETCH_TIMEOUT_MS,
153
+ });
154
+ }
155
+ catch (err) {
156
+ const e = err;
157
+ if (e.name === 'AbortError' || e.name === 'TimeoutError') {
158
+ throw new StatusToolError(`Report fetch timed out after ${REPORT_FETCH_TIMEOUT_MS / 1000}s. Job ${jobId} is complete — view it at ${webJobUrl(deps.config, jobId)}.`, { jobId });
159
+ }
160
+ throw err;
161
+ }
162
+ if (!reportResponse.ok) {
163
+ throw new StatusToolError(`Job ${jobId} is complete but the report could not be fetched (HTTP ${reportResponse.status}). View it at ${webJobUrl(deps.config, jobId)}.`, { jobId });
164
+ }
165
+ const reportJson = (await reportResponse.json().catch(() => null));
166
+ if (!reportJson?.reportMarkdown) {
167
+ throw new StatusToolError(`Job ${jobId} reports complete but the report is empty. View it at ${webJobUrl(deps.config, jobId)}.`, { jobId });
168
+ }
169
+ const rawReportData = reportJson.reportData ?? null;
170
+ let reportData = rawReportData;
171
+ if (rawReportData) {
172
+ const parsedReport = ResearchReportDataSchema.safeParse(rawReportData);
173
+ if (parsedReport.success) {
174
+ reportData = parsedReport.data;
175
+ }
176
+ else {
177
+ // Same passthrough behavior as runResearch — never drop data on
178
+ // schema drift; log to stderr so operators see the drift signal.
179
+ console.error('[clien-mcp] status: report_data failed schema validation; passing through raw payload:', parsedReport.error.issues[0]);
180
+ }
181
+ }
182
+ return {
183
+ content: [{ type: 'text', text: reportJson.reportMarkdown }],
184
+ _meta: {
185
+ job_id: jobId,
186
+ status: reportJson.status ?? status,
187
+ done: true,
188
+ report_data: reportData,
189
+ ...(totalCostCents !== undefined ? { total_cost_cents: totalCostCents } : {}),
190
+ ...(lastSequence !== undefined ? { last_sequence: lastSequence } : {}),
191
+ },
192
+ };
193
+ }
194
+ // 3. Terminal-failed / cancelled path: brief text summary so the host
195
+ // AI can explain the outcome. Avoids a second HTTP call.
196
+ if (status === 'failed' || status === 'cancelled') {
197
+ const summary = summarizeLatestEvent(eventsJson?.events);
198
+ const reason = summary ? ` Latest event: ${summary}` : '';
199
+ return {
200
+ content: [
201
+ {
202
+ type: 'text',
203
+ text: `Job ${jobId} ended with status "${status}".${reason}\n\n` +
204
+ `Full details at ${webJobUrl(deps.config, jobId)}.`,
205
+ },
206
+ ],
207
+ _meta: {
208
+ job_id: jobId,
209
+ status,
210
+ done: true,
211
+ ...(totalCostCents !== undefined ? { total_cost_cents: totalCostCents } : {}),
212
+ ...(lastSequence !== undefined ? { last_sequence: lastSequence } : {}),
213
+ },
214
+ };
215
+ }
216
+ // 4. Still running. Brief activity snapshot so the host AI can decide
217
+ // whether to wait and call again, or surface progress to the user.
218
+ const latest = summarizeLatestEvent(eventsJson?.events);
219
+ const activity = latest ? `Latest activity: ${latest}.` : 'No recent activity events.';
220
+ return {
221
+ content: [
222
+ {
223
+ type: 'text',
224
+ text: `Job ${jobId} is still running. Current phase: "${status}". ` +
225
+ `${activity}\n\n` +
226
+ `Call clien_research_status with this same job_id again in a minute ` +
227
+ `or two to check progress, or view live updates at ${webJobUrl(deps.config, jobId)}.`,
228
+ },
229
+ ],
230
+ _meta: {
231
+ job_id: jobId,
232
+ status,
233
+ done: false,
234
+ ...(totalCostCents !== undefined ? { total_cost_cents: totalCostCents } : {}),
235
+ ...(lastSequence !== undefined ? { last_sequence: lastSequence } : {}),
236
+ },
237
+ };
238
+ }
239
+ /**
240
+ * No-`job_id` recovery. Lists the caller's recent runs via `GET /api/validate`
241
+ * (account-scoped, so a caller with two Claude windows sees both) and selects
242
+ * SAFELY by active-run count:
243
+ * - exactly one active run → resume it,
244
+ * - more than one active run → return a disambiguation list; NEVER guess
245
+ * (guessing could hand a session recovering idea A the run for idea B),
246
+ * - no active runs → resume the sole recent run if unambiguous, else list.
247
+ */
248
+ async function resolveJobId(ctx, deps) {
249
+ let listResponse;
250
+ try {
251
+ listResponse = await apiCall(ctx, 'GET', `/api/validate?limit=${LIST_LIMIT}`, {
252
+ acceptJson: true,
253
+ timeoutMs: LIST_FETCH_TIMEOUT_MS,
254
+ });
255
+ }
256
+ catch (err) {
257
+ const e = err;
258
+ if (e.name === 'AbortError' || e.name === 'TimeoutError') {
259
+ throw new StatusToolError(`Timed out looking up your recent research runs after ${LIST_FETCH_TIMEOUT_MS / 1000}s. Try again in a moment.`);
260
+ }
261
+ throw err;
262
+ }
263
+ if (!listResponse.ok) {
264
+ const category = categorizeFetchError(listResponse.status);
265
+ if (category === 'auth') {
266
+ if (listResponse.refreshError?.kind !== 'transient') {
267
+ deps.invalidateSession?.();
268
+ }
269
+ throw new StatusToolError('Session expired. Re-run clien_research to re-authenticate, then retry recovery.');
270
+ }
271
+ const text = await listResponse.text().catch(() => '');
272
+ throw new StatusToolError(`Failed to look up recent research runs (HTTP ${listResponse.status}): ${truncate(text, 200)}`);
273
+ }
274
+ const listJson = (await listResponse.json().catch(() => null));
275
+ const jobs = (listJson?.jobs ?? []).filter((j) => typeof j.id === 'string');
276
+ if (jobs.length === 0) {
277
+ throw new StatusToolError('No recent research runs found for this account. If you just started one, wait a few ' +
278
+ 'seconds and try again; otherwise start a new run with clien_research.');
279
+ }
280
+ const active = jobs.filter((j) => ACTIVE_STATUSES.has(j.status ?? ''));
281
+ const [firstActive] = active;
282
+ if (firstActive && active.length === 1) {
283
+ return { kind: 'job', jobId: firstActive.id };
284
+ }
285
+ if (active.length > 1) {
286
+ return { kind: 'disambiguate', result: buildDisambiguation(active, 'active') };
287
+ }
288
+ // No active runs: resume the single recent run if unambiguous, else list.
289
+ const [firstJob] = jobs;
290
+ if (firstJob && jobs.length === 1) {
291
+ return { kind: 'job', jobId: firstJob.id };
292
+ }
293
+ return { kind: 'disambiguate', result: buildDisambiguation(jobs, 'recent') };
294
+ }
295
+ function buildDisambiguation(jobs, kind) {
296
+ const runs = jobs.map((j) => ({
297
+ job_id: j.id,
298
+ idea: truncate((j.prompt ?? '').trim() || '(no idea text)', IDEA_SNIPPET_MAX),
299
+ status: j.status ?? 'unknown',
300
+ started_at: j.createdAt ?? '',
301
+ ...(j.projectId ? { project_id: j.projectId } : {}),
302
+ }));
303
+ const label = kind === 'active' ? 'active (in-flight)' : 'recent';
304
+ const lines = runs
305
+ .map((r, i) => {
306
+ const started = r.started_at ? `, started ${r.started_at}` : '';
307
+ return `${i + 1}. job_id: ${r.job_id}\n idea: "${r.idea}"\n status: ${r.status}${started}`;
308
+ })
309
+ .join('\n');
310
+ const text = `Found ${runs.length} ${label} research runs on this account and can't tell which one ` +
311
+ `you were executing. Pick the one whose idea matches what you asked to research, then ` +
312
+ `call clien_research_status again with that job_id.\n\n${lines}`;
313
+ return {
314
+ content: [{ type: 'text', text }],
315
+ _meta: { needs_disambiguation: true, runs },
316
+ };
317
+ }
318
+ function summarizeLatestEvent(events) {
319
+ if (!events || events.length === 0)
320
+ return null;
321
+ const last = events[events.length - 1];
322
+ if (!last)
323
+ return null;
324
+ const type = last.eventType ?? 'event';
325
+ const data = last.eventData ?? {};
326
+ if (typeof data.message === 'string' && data.message.length > 0) {
327
+ return truncate(`${type}: ${data.message}`, 160);
328
+ }
329
+ if (typeof data.phase === 'string') {
330
+ return truncate(`${type}: ${data.phase}`, 160);
331
+ }
332
+ return type;
333
+ }
334
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/tools/status.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clien-ai/mcp",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Clien.ai MCP server — deep product research from Claude Code.",
5
5
  "keywords": [
6
6
  "mcp",