@rockhopper-co/mcp-server 2.0.1 → 2.1.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.
Files changed (54) hide show
  1. package/README.md +2 -1
  2. package/dist/api-client.d.ts +136 -2
  3. package/dist/api-client.d.ts.map +1 -1
  4. package/dist/api-client.js +185 -2
  5. package/dist/api-client.js.map +1 -1
  6. package/dist/capabilities.d.ts +5 -6
  7. package/dist/capabilities.d.ts.map +1 -1
  8. package/dist/capabilities.js +6 -9
  9. package/dist/capabilities.js.map +1 -1
  10. package/dist/drive-search.d.ts +162 -0
  11. package/dist/drive-search.d.ts.map +1 -0
  12. package/dist/drive-search.js +210 -0
  13. package/dist/drive-search.js.map +1 -0
  14. package/dist/enrollment.d.ts +121 -0
  15. package/dist/enrollment.d.ts.map +1 -0
  16. package/dist/enrollment.js +247 -0
  17. package/dist/enrollment.js.map +1 -0
  18. package/dist/resources/orchestration-guide.md +58 -8
  19. package/dist/tools/connect-microsoft.d.ts +21 -0
  20. package/dist/tools/connect-microsoft.d.ts.map +1 -0
  21. package/dist/tools/connect-microsoft.js +138 -0
  22. package/dist/tools/connect-microsoft.js.map +1 -0
  23. package/dist/tools/drive-search-lanes.d.ts +65 -0
  24. package/dist/tools/drive-search-lanes.d.ts.map +1 -0
  25. package/dist/tools/drive-search-lanes.js +95 -0
  26. package/dist/tools/drive-search-lanes.js.map +1 -0
  27. package/dist/tools/drive-search.contract.d.ts +94 -0
  28. package/dist/tools/drive-search.contract.d.ts.map +1 -0
  29. package/dist/tools/drive-search.contract.js +235 -0
  30. package/dist/tools/drive-search.contract.js.map +1 -0
  31. package/dist/tools/drive-search.d.ts +31 -0
  32. package/dist/tools/drive-search.d.ts.map +1 -0
  33. package/dist/tools/drive-search.js +209 -0
  34. package/dist/tools/drive-search.js.map +1 -0
  35. package/dist/tools/enroll-file.contract.d.ts +52 -0
  36. package/dist/tools/enroll-file.contract.d.ts.map +1 -0
  37. package/dist/tools/enroll-file.contract.js +105 -0
  38. package/dist/tools/enroll-file.contract.js.map +1 -0
  39. package/dist/tools/enroll-file.d.ts +4 -0
  40. package/dist/tools/enroll-file.d.ts.map +1 -0
  41. package/dist/tools/enroll-file.js +184 -0
  42. package/dist/tools/enroll-file.js.map +1 -0
  43. package/dist/tools/index.d.ts.map +1 -1
  44. package/dist/tools/index.js +12 -0
  45. package/dist/tools/index.js.map +1 -1
  46. package/dist/tools/search.d.ts.map +1 -1
  47. package/dist/tools/search.js +25 -2
  48. package/dist/tools/search.js.map +1 -1
  49. package/dist/tools/write-files.d.ts.map +1 -1
  50. package/dist/tools/write-files.js +5 -0
  51. package/dist/tools/write-files.js.map +1 -1
  52. package/dist/types.d.ts +150 -0
  53. package/dist/types.d.ts.map +1 -1
  54. package/package.json +2 -2
@@ -0,0 +1,209 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { inputRequired, inputResponse, } from '@modelcontextprotocol/server';
3
+ import { CandidateRegistry, SearchBudget, classifyDriveSearchFailure, ADMIN_CONSENT_TEXT, isAdminConsentRequired, isNoDelegatedToken, toCandidate, } from '../drive-search.js';
4
+ import { log } from '../logger.js';
5
+ import { BUDGET_EXHAUSTED_TEXT, DECLINE_CHOICE, DRIVE_SEARCH_ANNOTATIONS, DRIVE_SEARCH_DESCRIPTION, DRIVE_SEARCH_INPUT_SCHEMA, confirmationForm, confirmationPrompt, confirmedAnswer, connectPrompt, declinedAnswer, toolResult, unknownCandidateAnswer, } from './drive-search.contract.js';
6
+ import { CONFIRM_KEY, readRequestState, selectLane, } from './drive-search-lanes.js';
7
+ /**
8
+ * ENG-2204 (SP08) — the half of ENG-1647 that ENG-2200 did not fix.
9
+ *
10
+ * ENG-2200 built the enroll tool the customer could not find. This finds the
11
+ * FILE: a workbook Rockhopper has never seen, in the user's own OneDrive or
12
+ * SharePoint, confirmed with them before anything is written.
13
+ *
14
+ * Three things here are load-bearing and none is obvious from the happy path:
15
+ *
16
+ * 1. **The search set IS the permission trim.** Every candidate came back from
17
+ * a delegated Microsoft call made as this user. Nothing is added to it,
18
+ * nothing is inferred into it, and no file outside it is ever offered.
19
+ * 2. **A confirmation resolves against SERVER memory, never against what the
20
+ * client sent.** The confirmation carries a position and a nonce; the file
21
+ * it names is looked up in the set this session actually returned. A model
22
+ * that has read a hostile file name cannot conjure a `driveMsId` and have
23
+ * the tool bless it.
24
+ * 3. **The budget is claimed BEFORE the network call.** A cap that discards an
25
+ * answer already fetched has not capped anything — the enumeration already
26
+ * happened, and Microsoft already answered it.
27
+ */
28
+ export function registerDriveSearchTool(server, api, session) {
29
+ // Per-server, never per-module: two servers in one process (a test file, a
30
+ // gateway serving two sessions) must not share a ceiling, and a module-level
31
+ // counter is exactly the shape that silently does.
32
+ const budget = session?.budget ?? new SearchBudget();
33
+ const registry = session?.registry ?? new CandidateRegistry();
34
+ /**
35
+ * Resolve a (nonce, position) pair against what this session offered.
36
+ *
37
+ * Position, never identifier — the only thing a client can send is a number,
38
+ * and a number that does not index a set this session returned resolves to
39
+ * nothing. `0` and the elicitation form's "none of these" are the same
40
+ * answer: the user was asked and chose no file.
41
+ */
42
+ function resolvePick(nonce, choice) {
43
+ if (choice === DECLINE_CHOICE || choice === 0)
44
+ return declinedAnswer();
45
+ if (!nonce)
46
+ return unknownCandidateAnswer();
47
+ const position = typeof choice === 'number' ? choice : Number(choice);
48
+ const candidate = registry.resolve(nonce, position - 1);
49
+ return candidate ? confirmedAnswer(candidate) : unknownCandidateAnswer();
50
+ }
51
+ /**
52
+ * Put the question through the best lane this request can reach.
53
+ *
54
+ * Lane 2 is awaited INSIDE the call and lane 3 returns out of it; both end
55
+ * at the same three answers, and lane 1 hands the question to the model.
56
+ */
57
+ async function ask(ctx, candidates, nonce) {
58
+ const lane = selectLane(ctx, server.server?.getClientCapabilities?.());
59
+ const form = confirmationForm(candidates);
60
+ if (lane === 'input_required') {
61
+ return inputRequired({
62
+ inputRequests: { [CONFIRM_KEY]: inputRequired.elicit(form) },
63
+ requestState: nonce,
64
+ });
65
+ }
66
+ if (lane === 'elicitation' && ctx?.mcpReq?.elicitInput) {
67
+ try {
68
+ const answer = await ctx.mcpReq.elicitInput({ ...form, mode: 'form' });
69
+ if (answer?.action === 'accept') {
70
+ const choice = answer.content
71
+ ?.choice;
72
+ return resolvePick(nonce, choice ?? DECLINE_CHOICE);
73
+ }
74
+ // Declined or cancelled. Both mean the user did not choose a file, and
75
+ // neither is an error: a person is allowed to say no.
76
+ return declinedAnswer();
77
+ }
78
+ catch {
79
+ // The client advertised elicitation and could not deliver it. Falling
80
+ // back to the universal lane keeps the question answerable instead of
81
+ // turning a capability mismatch into a dead end.
82
+ }
83
+ }
84
+ return toolResult({
85
+ outcome: 'candidates',
86
+ text: confirmationPrompt(candidates, nonce),
87
+ detail: { confirmToken: nonce, candidateCount: candidates.length },
88
+ });
89
+ }
90
+ server.registerTool('search_drive_files', {
91
+ title: "Find a File in the User's Microsoft Drive",
92
+ description: DRIVE_SEARCH_DESCRIPTION,
93
+ inputSchema: DRIVE_SEARCH_INPUT_SCHEMA,
94
+ annotations: DRIVE_SEARCH_ANNOTATIONS,
95
+ }, async ({ query, scope, limit, confirm_index, confirm_token }, ctx) => {
96
+ // A retried multi-round-trip request arrives with the user's answer
97
+ // embedded. It is checked FIRST and it never searches again: re-running
98
+ // the query on a retry would spend a second unit of budget and could
99
+ // return a different set than the one the user was looking at.
100
+ const embedded = inputResponse(ctx?.mcpReq?.inputResponses, CONFIRM_KEY);
101
+ if (embedded.kind === 'elicit') {
102
+ if (embedded.action !== 'accept')
103
+ return declinedAnswer();
104
+ const choice = embedded.content
105
+ ?.choice;
106
+ return resolvePick(readRequestState(ctx), choice ?? DECLINE_CHOICE);
107
+ }
108
+ // The universal lane's confirmation: the model relaying a number the
109
+ // user said out loud. Same resolution, same server-side lookup.
110
+ if (confirm_index !== undefined || confirm_token !== undefined) {
111
+ return resolvePick(confirm_token ?? null, confirm_index ?? NaN);
112
+ }
113
+ if (!budget.claim()) {
114
+ log.warn({
115
+ event: 'drive_search_capped',
116
+ searches: budget.spent,
117
+ budget: budget.ceiling,
118
+ }, 'drive_search_capped');
119
+ return toolResult({
120
+ outcome: 'search_limit_reached',
121
+ isError: true,
122
+ text: BUDGET_EXHAUSTED_TEXT,
123
+ detail: { searchesUsed: budget.spent, searchBudget: budget.ceiling },
124
+ });
125
+ }
126
+ let items;
127
+ try {
128
+ const answer = await api.searchDriveFiles({
129
+ q: query,
130
+ scope,
131
+ limit: limit ?? 10,
132
+ });
133
+ items = answer.items;
134
+ }
135
+ catch (error) {
136
+ // ORDER MATTERS. Both refusals arrive as `NO_DELEGATED_TOKEN`, so
137
+ // checking "not connected" first would swallow the administrator
138
+ // case and hand the user a connect link that Microsoft refuses —
139
+ // which returns them here, with the same link, forever (ENG-2614).
140
+ if (isAdminConsentRequired(error)) {
141
+ return toolResult({
142
+ outcome: 'microsoft_admin_approval_required',
143
+ text: ADMIN_CONSENT_TEXT,
144
+ isError: true,
145
+ });
146
+ }
147
+ if (isNoDelegatedToken(error))
148
+ return connectAnswer(api);
149
+ const { outcome, message } = classifyDriveSearchFailure(error);
150
+ return toolResult({ outcome, text: message, isError: true });
151
+ }
152
+ // Mirrors the backend's own discovery log (`[DRIVE-SEARCH]`): the query
153
+ // LENGTH, never its text, and a count, never a name. Enough to tell an
154
+ // empty probe from a real one while reading an incident, and none of the
155
+ // customer's content.
156
+ log.info({
157
+ event: 'drive_search',
158
+ scope: scope ?? 'search',
159
+ queryLength: query?.length ?? 0,
160
+ results: items.length,
161
+ searches: budget.spent,
162
+ budget: budget.ceiling,
163
+ }, 'drive_search');
164
+ if (items.length === 0) {
165
+ return toolResult({
166
+ outcome: 'no_matches',
167
+ text: 'Microsoft returned no spreadsheets matching that. The search ran ' +
168
+ 'and came back empty — it did not fail. Ask the user to try a ' +
169
+ 'different part of the name, or call again with scope="recent" ' +
170
+ 'to list what they have worked on lately.',
171
+ });
172
+ }
173
+ const candidates = items.map(toCandidate);
174
+ const nonce = randomUUID();
175
+ registry.remember(nonce, candidates);
176
+ return ask(ctx, candidates, nonce);
177
+ });
178
+ }
179
+ /**
180
+ * The `NO_DELEGATED_TOKEN` answer: a link the BACKEND built.
181
+ *
182
+ * The tool takes no authorize URL, no redirect and no client id, and it never
183
+ * asks the model to compose one. An MCP tool's arguments are chosen by a model
184
+ * reading content it did not author, so a caller-supplied sign-in link is a
185
+ * consent-phishing lever — the user would see a genuine Microsoft consent
186
+ * screen the whole way while approving somebody else's application. Same
187
+ * reasoning as `connect_microsoft`, which is where this link comes from.
188
+ */
189
+ async function connectAnswer(api) {
190
+ try {
191
+ const handoff = await api.beginMicrosoftConnect();
192
+ return toolResult({
193
+ outcome: 'microsoft_not_connected',
194
+ text: connectPrompt(handoff.authorizeUrl, handoff.expiresAt),
195
+ detail: { authorizeUrl: handoff.authorizeUrl },
196
+ });
197
+ }
198
+ catch {
199
+ return toolResult({
200
+ outcome: 'microsoft_not_connected',
201
+ isError: true,
202
+ text: 'This user has no connected Microsoft account, and Rockhopper could ' +
203
+ 'not produce a sign-in link just now. Ask them to run ' +
204
+ '`connect_microsoft`, or to paste the workbook link for `enroll_file`. ' +
205
+ 'Do not compose a Microsoft sign-in link yourself.',
206
+ });
207
+ }
208
+ }
209
+ //# sourceMappingURL=drive-search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drive-search.js","sourceRoot":"","sources":["../../src/tools/drive-search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * ENG-2200 — everything `enroll_file` SAYS, split from everything it DOES
3
+ * (`enroll-file.ts`).
4
+ *
5
+ * The seam is not arbitrary. This half is the only interface a language model
6
+ * ever sees: it cannot read the handler, so the schema descriptions and the
7
+ * tool description ARE the contract, and a wrong word here is a behaviour bug
8
+ * that no type checks. Keeping it apart means it can be reviewed as prose —
9
+ * and read by a person deciding whether a model would do the right thing —
10
+ * without the branch logic in the way.
11
+ */
12
+ import { z } from 'zod';
13
+ import type { EnrollOutcome } from '../enrollment.js';
14
+ export declare const ENROLL_INPUT_SCHEMA: z.ZodObject<{
15
+ url: z.ZodOptional<z.ZodString>;
16
+ driveMsId: z.ZodOptional<z.ZodString>;
17
+ msId: z.ZodOptional<z.ZodString>;
18
+ share_with: z.ZodOptional<z.ZodEnum<{
19
+ me: "me";
20
+ team: "team";
21
+ }>>;
22
+ confirm_restore: z.ZodOptional<z.ZodBoolean>;
23
+ }, z.core.$strip>;
24
+ export declare const ENROLL_DESCRIPTION: string;
25
+ export declare const ENROLL_ANNOTATIONS: {
26
+ readonly readOnlyHint: false;
27
+ readonly destructiveHint: false;
28
+ readonly idempotentHint: true;
29
+ readonly openWorldHint: true;
30
+ };
31
+ /** The question the model puts to the user when `share_with` was omitted. */
32
+ export declare const SHARE_QUESTION: string;
33
+ /** The machine-readable half of every answer, so a model can branch on it. */
34
+ export interface EnrollAnswer {
35
+ outcome: EnrollOutcome;
36
+ text: string;
37
+ isError?: boolean;
38
+ detail?: Record<string, unknown>;
39
+ }
40
+ /**
41
+ * Render an answer as a tool result: prose for the human, then one JSON line
42
+ * for the model. Both, because prose alone invites the model to paraphrase a
43
+ * refusal into a success, and JSON alone gives the user nothing to read.
44
+ */
45
+ export declare function toolResult(answer: EnrollAnswer): {
46
+ isError?: true | undefined;
47
+ content: {
48
+ type: "text";
49
+ text: string;
50
+ }[];
51
+ };
52
+ //# sourceMappingURL=enroll-file.contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enroll-file.contract.d.ts","sourceRoot":"","sources":["../../src/tools/enroll-file.contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,eAAO,MAAM,mBAAmB;;;;;;;;;iBAkD9B,CAAC;AAEH,eAAO,MAAM,kBAAkB,QAqB4C,CAAC;AAE5E,eAAO,MAAM,kBAAkB;;;;;CAQrB,CAAC;AAEX,6EAA6E;AAC7E,eAAO,MAAM,cAAc,QAG+C,CAAC;AAE3E,8EAA8E;AAC9E,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,aAAa,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,YAAY;;;;;;EAW9C"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * ENG-2200 — everything `enroll_file` SAYS, split from everything it DOES
3
+ * (`enroll-file.ts`).
4
+ *
5
+ * The seam is not arbitrary. This half is the only interface a language model
6
+ * ever sees: it cannot read the handler, so the schema descriptions and the
7
+ * tool description ARE the contract, and a wrong word here is a behaviour bug
8
+ * that no type checks. Keeping it apart means it can be reviewed as prose —
9
+ * and read by a person deciding whether a model would do the right thing —
10
+ * without the branch logic in the way.
11
+ */
12
+ import { z } from 'zod';
13
+ export const ENROLL_INPUT_SCHEMA = z.object({
14
+ url: z
15
+ .string()
16
+ .optional()
17
+ .describe("The workbook's SharePoint or OneDrive address, exactly as copied from " +
18
+ 'the browser bar. Use this whenever the user can paste a link — it is ' +
19
+ 'the only input that names one specific file with no guessing.'),
20
+ driveMsId: z
21
+ .string()
22
+ .optional()
23
+ .describe('Microsoft drive id. Only for a file already identified by another tool; ' +
24
+ 'must be sent together with `msId`, and never alongside `url`.'),
25
+ msId: z
26
+ .string()
27
+ .optional()
28
+ .describe('Microsoft drive-item id. Must be sent together with `driveMsId`, and ' +
29
+ 'never alongside `url`.'),
30
+ /**
31
+ * Optional in the SCHEMA and required by the HANDLER, deliberately.
32
+ *
33
+ * A required field turns an omission into a protocol-level validation error,
34
+ * and the model then sees a rejection instead of the question it is supposed
35
+ * to put to the user. D5/D6 say ask every time, so the tool answers an
36
+ * omission with the question. What it must never do is pick a value:
37
+ * enrolling privately when the user meant "my team" is invisible until
38
+ * somebody cannot find the file.
39
+ */
40
+ share_with: z
41
+ .enum(['me', 'team'])
42
+ .optional()
43
+ .describe('REQUIRED. Who may see this file: "me" (just the user) or "team" ' +
44
+ '(everyone on their team). ASK THE USER every time and use their ' +
45
+ 'answer — never assume, never carry an answer over from an earlier ' +
46
+ 'file. Omitting it does not enroll anything; the tool returns the ' +
47
+ 'question to put to them.'),
48
+ confirm_restore: z
49
+ .boolean()
50
+ .optional()
51
+ .describe('Set to true only after the user has confirmed they want a file they ' +
52
+ 'previously removed to be restored. Ignored otherwise.'),
53
+ });
54
+ export const ENROLL_DESCRIPTION = 'Add a Microsoft Excel workbook to Rockhopper so it can be versioned, ' +
55
+ "reviewed and tracked. Takes the file's SharePoint or OneDrive link (best), " +
56
+ 'or a `driveMsId` + `msId` pair. ' +
57
+ 'MICROSOFT ONLY — Google Sheets and Drive links are refused. ' +
58
+ 'You MUST ask the user who may see the file and pass their answer as ' +
59
+ '`share_with` ("me" or "team"); calling without it returns the question ' +
60
+ 'instead of enrolling. ' +
61
+ 'If the file was previously removed from Rockhopper, this reports ' +
62
+ '`restore_confirmation_required` and changes nothing — ask the user, then ' +
63
+ 'call again with `confirm_restore: true`. ' +
64
+ 'Safe to call again if you lose the answer: a file that is already there ' +
65
+ 'reports `already_enrolled` and is not duplicated. ' +
66
+ 'Use this whenever `search_files` or `list_files` cannot find a file the ' +
67
+ 'user is asking about — a file Rockhopper does not know about is not a ' +
68
+ 'missing file, it is an un-enrolled one. ' +
69
+ // ENG-2204: the `driveMsId` + `msId` pair has one honest source, and naming
70
+ // it here is what keeps a model from assembling a pair out of ids it read
71
+ // somewhere else and enrolling a file the user never named.
72
+ 'If the user cannot produce a link, call `search_drive_files` first, have ' +
73
+ 'them confirm which candidate they meant, and pass the `driveMsId` + `msId` ' +
74
+ 'that confirmation returned. Never enroll a file the user has not named.';
75
+ export const ENROLL_ANNOTATIONS = {
76
+ readOnlyHint: false,
77
+ // Enrolling adds a file; it never removes or overwrites one, and a repeat
78
+ // call on an already-enrolled file changes nothing.
79
+ destructiveHint: false,
80
+ idempotentHint: true,
81
+ // It reaches SharePoint / OneDrive through Rockhopper.
82
+ openWorldHint: true,
83
+ };
84
+ /** The question the model puts to the user when `share_with` was omitted. */
85
+ export const SHARE_QUESTION = 'Before this file can be added, ask the user: "Should this workbook be ' +
86
+ 'visible to just you, or to your whole team?" Then call `enroll_file` again ' +
87
+ 'with share_with="me" or share_with="team". Nothing has been added yet.';
88
+ /**
89
+ * Render an answer as a tool result: prose for the human, then one JSON line
90
+ * for the model. Both, because prose alone invites the model to paraphrase a
91
+ * refusal into a success, and JSON alone gives the user nothing to read.
92
+ */
93
+ export function toolResult(answer) {
94
+ const payload = { outcome: answer.outcome, ...(answer.detail ?? {}) };
95
+ return {
96
+ content: [
97
+ {
98
+ type: 'text',
99
+ text: `${answer.text}\n${JSON.stringify(payload)}`,
100
+ },
101
+ ],
102
+ ...(answer.isError ? { isError: true } : {}),
103
+ };
104
+ }
105
+ //# sourceMappingURL=enroll-file.contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enroll-file.contract.js","sourceRoot":"","sources":["../../src/tools/enroll-file.contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,GAAG,EAAE,CAAC;SACH,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,wEAAwE;QACtE,uEAAuE;QACvE,+DAA+D,CAClE;IACH,SAAS,EAAE,CAAC;SACT,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,0EAA0E;QACxE,+DAA+D,CAClE;IACH,IAAI,EAAE,CAAC;SACJ,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,uEAAuE;QACrE,wBAAwB,CAC3B;IACH;;;;;;;;;OASG;IACH,UAAU,EAAE,CAAC;SACV,IAAI,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;SACpB,QAAQ,EAAE;SACV,QAAQ,CACP,kEAAkE;QAChE,kEAAkE;QAClE,oEAAoE;QACpE,mEAAmE;QACnE,0BAA0B,CAC7B;IACH,eAAe,EAAE,CAAC;SACf,OAAO,EAAE;SACT,QAAQ,EAAE;SACV,QAAQ,CACP,sEAAsE;QACpE,uDAAuD,CAC1D;CACJ,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAC7B,uEAAuE;IACvE,6EAA6E;IAC7E,kCAAkC;IAClC,8DAA8D;IAC9D,sEAAsE;IACtE,yEAAyE;IACzE,wBAAwB;IACxB,mEAAmE;IACnE,2EAA2E;IAC3E,2CAA2C;IAC3C,0EAA0E;IAC1E,oDAAoD;IACpD,0EAA0E;IAC1E,wEAAwE;IACxE,0CAA0C;IAC1C,4EAA4E;IAC5E,0EAA0E;IAC1E,4DAA4D;IAC5D,2EAA2E;IAC3E,6EAA6E;IAC7E,yEAAyE,CAAC;AAE5E,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,YAAY,EAAE,KAAK;IACnB,0EAA0E;IAC1E,oDAAoD;IACpD,eAAe,EAAE,KAAK;IACtB,cAAc,EAAE,IAAI;IACpB,uDAAuD;IACvD,aAAa,EAAE,IAAI;CACX,CAAC;AAEX,6EAA6E;AAC7E,MAAM,CAAC,MAAM,cAAc,GACzB,wEAAwE;IACxE,6EAA6E;IAC7E,wEAAwE,CAAC;AAU3E;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,MAAoB;IAC7C,MAAM,OAAO,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC;IACtE,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,GAAG,MAAM,CAAC,IAAI,KAAK,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE;aACnD;SACF;QACD,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from '@modelcontextprotocol/server';
2
+ import type { ApiClient } from '../api-client.js';
3
+ export declare function registerEnrollFileTool(server: McpServer, api: ApiClient): void;
4
+ //# sourceMappingURL=enroll-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enroll-file.d.ts","sourceRoot":"","sources":["../../src/tools/enroll-file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAmDlD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,GAAG,IAAI,CA2N9E"}
@@ -0,0 +1,184 @@
1
+ import { classifyEnrollmentFailure, describeServerOutcome, outcomeForState, resolveTeamShareTargets, TeamUnresolvedError, } from '../enrollment.js';
2
+ import { ENROLL_ANNOTATIONS, ENROLL_DESCRIPTION, ENROLL_INPUT_SCHEMA, SHARE_QUESTION, toolResult, } from './enroll-file.contract.js';
3
+ export function registerEnrollFileTool(server, api) {
4
+ /**
5
+ * Turn whichever input arrived into `(identity, current state)`.
6
+ *
7
+ * Both branches learn the state BEFORE writing anything, because the whole
8
+ * point of the tool is that `enrolled`, `hidden` and `not_enrolled` lead to
9
+ * three different conversations.
10
+ */
11
+ async function resolveTarget(args) {
12
+ if (args.url) {
13
+ const resolved = await api.resolveEnrollmentUrl(args.url);
14
+ return {
15
+ msId: resolved.msId,
16
+ driveMsId: resolved.driveMsId,
17
+ name: resolved.name,
18
+ state: resolved.enrollmentState,
19
+ };
20
+ }
21
+ const msId = args.msId;
22
+ const driveMsId = args.driveMsId;
23
+ const [info] = await api.getEnrollmentInfo([msId]);
24
+ return {
25
+ msId,
26
+ driveMsId,
27
+ // The bulk read withholds `name` for a hidden or stub row, and an id
28
+ // enroll has no other source for it. The backend fills the real name
29
+ // from Graph during the enroll, so an empty string here is a placeholder
30
+ // that never reaches a user, not a guess at what the file is called.
31
+ name: info?.name ?? '',
32
+ state: info?.enrollmentState ?? 'not_enrolled',
33
+ };
34
+ }
35
+ /**
36
+ * ENG-2536 — the server's own verdict, or null when it did not give one.
37
+ *
38
+ * Null is not hypothetical: this package publishes to npm on its own clock
39
+ * and a customer's `npx` picks up `latest` immediately, so a backend that
40
+ * predates the field is a live case. The caller falls back to what the
41
+ * pre-write lookup said, which is exactly the behaviour that shipped before.
42
+ */
43
+ function serverOutcomeOf(queued, target) {
44
+ const files = queued.files ?? [];
45
+ const mine = files.find((f) => f.msId === target.msId || f.platformId === target.msId) ??
46
+ (files.length === 1 ? files[0] : undefined);
47
+ return mine?.outcome ?? null;
48
+ }
49
+ async function enroll(target, shareWith) {
50
+ const file = {
51
+ msId: target.msId,
52
+ driveMsId: target.driveMsId,
53
+ name: target.name,
54
+ };
55
+ if (shareWith === 'me') {
56
+ const queued = await api.createEnrolledFile(file);
57
+ return {
58
+ enrollmentId: queued.enrollmentId,
59
+ sharedWith: 0,
60
+ serverOutcome: serverOutcomeOf(queued, target),
61
+ };
62
+ }
63
+ const targets = await resolveTeamShareTargets(api);
64
+ const queued = await api.enrollFileSharedWith(file, targets);
65
+ return {
66
+ enrollmentId: queued.enrollmentId,
67
+ sharedWith: targets.length,
68
+ serverOutcome: serverOutcomeOf(queued, target),
69
+ };
70
+ }
71
+ server.registerTool('enroll_file', {
72
+ title: 'Add a File to Rockhopper',
73
+ description: ENROLL_DESCRIPTION,
74
+ inputSchema: ENROLL_INPUT_SCHEMA,
75
+ annotations: ENROLL_ANNOTATIONS,
76
+ }, async ({ url, driveMsId, msId, share_with, confirm_restore }) => {
77
+ const hasUrl = !!url?.trim();
78
+ const hasIds = !!msId?.trim() && !!driveMsId?.trim();
79
+ if (hasUrl && hasIds) {
80
+ return toolResult({
81
+ outcome: 'unresolvable',
82
+ isError: true,
83
+ text: 'Send either `url` or the `driveMsId` + `msId` pair, not both — ' +
84
+ 'they can name different files and Rockhopper will not guess ' +
85
+ 'which one you meant. Nothing was changed.',
86
+ });
87
+ }
88
+ if (!hasUrl && !hasIds) {
89
+ return toolResult({
90
+ outcome: 'unresolvable',
91
+ isError: true,
92
+ text: 'No file was named. Ask the user to open the workbook and paste ' +
93
+ 'the address from their browser bar, then call `enroll_file` with ' +
94
+ 'that `url`. Nothing was changed.',
95
+ });
96
+ }
97
+ // Checked BEFORE the resolve so an omitted `share_with` costs no network
98
+ // call and, more importantly, cannot be answered by a half-done enroll.
99
+ if (share_with === undefined) {
100
+ return toolResult({
101
+ outcome: 'share_with_required',
102
+ text: SHARE_QUESTION,
103
+ });
104
+ }
105
+ let target;
106
+ try {
107
+ target = await resolveTarget({ url, driveMsId, msId });
108
+ }
109
+ catch (error) {
110
+ const { outcome, message } = classifyEnrollmentFailure(error);
111
+ return toolResult({
112
+ outcome: outcome === 'error' ? 'unresolvable' : outcome,
113
+ text: outcome === 'error'
114
+ ? `Rockhopper could not look that file up: ${message}`
115
+ : message,
116
+ isError: true,
117
+ });
118
+ }
119
+ const known = outcomeForState(target.state);
120
+ if (known === 'already_enrolled') {
121
+ return toolResult({
122
+ outcome: 'already_enrolled',
123
+ text: `"${target.name}" is already in Rockhopper — nothing to do. Its ` +
124
+ 'versions and history are available through `get_file_versions` ' +
125
+ 'and `get_cell_history`.',
126
+ detail: { fileMsId: target.msId, name: target.name },
127
+ });
128
+ }
129
+ if (known === 'restore_confirmation_required' && !confirm_restore) {
130
+ return toolResult({
131
+ outcome: 'restore_confirmation_required',
132
+ text: `"${target.name || 'That workbook'}" was previously removed from ` +
133
+ 'Rockhopper\'s file lists. Its versions, comments and history were ' +
134
+ 'kept. Ask the user whether they want it restored, and if they do, ' +
135
+ 'call `enroll_file` again with the same arguments plus ' +
136
+ 'confirm_restore: true. Nothing has been changed.',
137
+ detail: { fileMsId: target.msId, name: target.name || null },
138
+ });
139
+ }
140
+ const restoring = known === 'restore_confirmation_required';
141
+ try {
142
+ const { enrollmentId, sharedWith, serverOutcome } = await enroll(target, share_with);
143
+ const who = share_with === 'team'
144
+ ? ` and shared with ${sharedWith} teammate(s)`
145
+ : ' — visible to you only';
146
+ // ENG-2536: the SERVER's verdict wins over the one inferred from the
147
+ // lookup taken before the write. The two can disagree, and when they
148
+ // do the server is right: the lookup happened earlier, so a file
149
+ // somebody else added in between reads `not_enrolled` here and would
150
+ // otherwise be reported as a fresh add. The fallback is what shipped
151
+ // before, for a backend older than the field.
152
+ const { outcome, text } = describeServerOutcome(serverOutcome ?? (restoring ? 'restored' : 'enrolled'), target.name, who);
153
+ return toolResult({
154
+ outcome,
155
+ text,
156
+ detail: {
157
+ fileMsId: target.msId,
158
+ name: target.name || null,
159
+ enrollmentId,
160
+ shareWith: share_with,
161
+ sharedWithCount: sharedWith,
162
+ },
163
+ });
164
+ }
165
+ catch (error) {
166
+ if (error instanceof TeamUnresolvedError) {
167
+ return toolResult({
168
+ outcome: 'share_with_required',
169
+ text: error.message,
170
+ isError: true,
171
+ });
172
+ }
173
+ const { outcome, message } = classifyEnrollmentFailure(error);
174
+ return toolResult({
175
+ outcome: outcome === 'error' ? 'unresolvable' : outcome,
176
+ text: outcome === 'error'
177
+ ? `Rockhopper could not add that file: ${message}`
178
+ : message,
179
+ isError: true,
180
+ });
181
+ }
182
+ });
183
+ }
184
+ //# sourceMappingURL=enroll-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enroll-file.js","sourceRoot":"","sources":["../../src/tools/enroll-file.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,oBAAoB,CAAC;AAY5B,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,yBAAyB,EACzB,8BAA8B,EAC9B,KAAK,aAAa,GACnB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,oBAAoB;IACnC;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;;;;;;;;OAaG;IACH,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC;AAcD,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEnE;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,CAAC,EAAE,oBAAoB,GAC7B,aAAa,EAAE,CAUjB;AAWD,wBAAgB,aAAa,CAC3B,MAAM,EAAE,SAAS,EACjB,GAAG,EAAE,SAAS,EACd,OAAO,CAAC,EAAE,oBAAoB,GAC7B,IAAI,CAcN"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,oBAAoB,CAAC;AAc5B,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,yBAAyB,EACzB,8BAA8B,EAC9B,KAAK,aAAa,GACnB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,oBAAoB;IACnC;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;;;;;;;;OAaG;IACH,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC;AAcD,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEnE;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,CAAC,EAAE,oBAAoB,GAC7B,aAAa,EAAE,CAUjB;AAWD,wBAAgB,aAAa,CAC3B,MAAM,EAAE,SAAS,EACjB,GAAG,EAAE,SAAS,EACd,OAAO,CAAC,EAAE,oBAAoB,GAC7B,IAAI,CAwBN"}
@@ -5,6 +5,8 @@ import { registerGetCommentsTool } from './get-comments.js';
5
5
  import { registerGetReviewsTool } from './get-reviews.js';
6
6
  import { registerGetCellHistoryTool } from './get-cell-history.js';
7
7
  import { registerSearchTool } from './search.js';
8
+ import { registerDriveSearchTool } from './drive-search.js';
9
+ import { registerConnectMicrosoftTool } from './connect-microsoft.js';
8
10
  import { registerWriteCommentTools } from './write-comments.js';
9
11
  import { registerWriteReviewTools } from './write-reviews.js';
10
12
  import { registerWriteVersionTools } from './write-versions.js';
@@ -55,6 +57,16 @@ export function registerTools(server, api, options) {
55
57
  registerGetReviewsTool(server, api);
56
58
  registerGetCellHistoryTool(server, api);
57
59
  registerSearchTool(server, api);
60
+ // ENG-2204 — discovery of files Rockhopper has NEVER seen. On the read floor
61
+ // for the same reason `connect_microsoft` is: finding a file writes nothing,
62
+ // and a read-only token is exactly the caller who needs to be told a file is
63
+ // un-enrolled rather than missing.
64
+ registerDriveSearchTool(server, api);
65
+ // ENG-2198 — connecting a Microsoft account is an account action, not a
66
+ // write to Rockhopper data, so it rides with the read floor: a read-only
67
+ // token can still connect, check and disconnect. The backend requires an
68
+ // interactive login for the disconnect itself.
69
+ registerConnectMicrosoftTool(server, api);
58
70
  // Write tools — one registrar per granted family, so a token holding
59
71
  // `comments:write` alone cannot reach `discard_changes`.
60
72
  for (const capability of resolveCapabilities(options)) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,cAAc,EACd,gBAAgB,GAEjB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,yBAAyB,EACzB,8BAA8B,GAE/B,MAAM,oBAAoB,CAAC;AAiC5B;;;;;;;;;GASG;AACH,MAAM,YAAY,GAAwB,IAAI,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;AAElE,gFAAgF;AAChF,MAAM,UAAU,gBAAgB,CAAC,KAAyB;IACxD,OAAO,KAAK,KAAK,SAAS,IAAI,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACxD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CACjC,OAA8B;IAE9B,IAAI,OAAO,EAAE,YAAY,KAAK,SAAS,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,IAAI,GAAG,CACnB,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAsB,EAAE,CACpD,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,CACtB,CACF,CAAC;QACF,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,GAEZ;IACF,gBAAgB,EAAE,yBAAyB;IAC3C,eAAe,EAAE,wBAAwB;IACzC,gBAAgB,EAAE,yBAAyB;IAC3C,aAAa,EAAE,qBAAqB;CACrC,CAAC;AAEF,MAAM,UAAU,aAAa,CAC3B,MAAiB,EACjB,GAAc,EACd,OAA8B;IAE9B,0EAA0E;IAC1E,qBAAqB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACnC,uBAAuB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACrC,uBAAuB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACrC,sBAAsB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACpC,0BAA0B,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACxC,kBAAkB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAEhC,qEAAqE;IACrE,yDAAyD;IACzD,KAAK,MAAM,UAAU,IAAI,mBAAmB,CAAC,OAAO,CAAC,EAAE,CAAC;QACtD,UAAU,CAAC,UAAU,CAAC,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACtC,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAE9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAOlD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,EACjB,GAAG,EAAE,SAAS,GACb,IAAI,CAuNN"}
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAE9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAOlD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,EACjB,GAAG,EAAE,SAAS,GACb,IAAI,CA8ON"}