@typelets/mcp 0.3.0 → 0.5.0

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 CHANGED
@@ -28,12 +28,13 @@ Why not session cookies: cookies are scoped to a browser and expire on the platf
28
28
 
29
29
  The PAT issuance flow is the only prerequisite work on the Typelets side. Everything else in this repo just wraps existing endpoints.
30
30
 
31
- ## Two profiles
31
+ ## Profiles
32
32
 
33
- The server ships two profiles:
33
+ The server ships three profiles:
34
34
 
35
35
  - **`interviewer`** (default): has access to rubric content, hidden tests, scores, and the full library.
36
- - **`candidate`** (strict): hides rubric / hidden tests / scores even if the user's role would otherwise allow it. Useful when the user wants to point an AI assistant at their own in-progress interview without leaking the answer key into the LLM's context.
36
+ - **`general`**: for using Typelets as a hosted dev/workspace product rather than for interviews. Full authoring workspace lifecycle (create/delete), file/folder CRUD, and reads — but none of the interview tooling (no problem authoring, no recording analysis or rubric scoring). Any problem content it reads is stripped of rubric / criteria / hidden tests / solution.
37
+ - **`candidate`** (strict): hides rubric / hidden tests / scores even if the user's role would otherwise allow it, and additionally withholds workspace lifecycle + problem tooling. Useful when the user wants to point an AI assistant at their own in-progress interview without leaking the answer key into the LLM's context.
37
38
 
38
39
  The profile is set at start-up, not per-tool:
39
40
 
@@ -41,7 +42,7 @@ The profile is set at start-up, not per-tool:
41
42
  TYPELETS_PROFILE=candidate npx @typelets/mcp
42
43
  ```
43
44
 
44
- Default is `interviewer`. The server refuses to switch profiles at runtime. If you want both, run two server instances on different ports.
45
+ Default is `interviewer`. The server refuses to switch profiles at runtime. If you want more than one, run a server instance per profile.
45
46
 
46
47
  ## Install
47
48
 
@@ -71,11 +72,12 @@ Get your token at https://typelets.com: User Settings → Tokens → New token.
71
72
 
72
73
  Profiles:
73
74
  - `interviewer` (default): full surface, including rubric and hidden tests.
74
- - `candidate`: the same tools but rubric, criteria, hidden tests, and solution are stripped before they reach the LLM. Use this when you want an AI assistant helping you on a problem you're solving.
75
+ - `general`: workspace lifecycle + file/folder CRUD + reads; no interview tooling. Use this when you're using Typelets as a hosted dev/workspace product.
76
+ - `candidate`: file CRUD + reads only; rubric, criteria, hidden tests, and solution are stripped before they reach the LLM. Use this when you want an AI assistant helping you on a problem you're solving.
75
77
 
76
78
  ## Tool surface
77
79
 
78
- 16 tools total. In `candidate` profile, the 5 interviewer-only tools are not registered; the candidate's host LLM does not see them in `listTools`.
80
+ In `general` profile the interview-authoring + session-intelligence tools are not registered; in `candidate` profile those plus workspace lifecycle (create/delete) are withheld. In each case the host LLM does not see the withheld tools in `listTools`.
79
81
 
80
82
  ### Reads (8 tools, both profiles)
81
83
 
@@ -95,9 +97,12 @@ Profiles:
95
97
  | Tool | Writes | `destructive` |
96
98
  | --- | --- | --- |
97
99
  | `create_file` | `POST /workspaces/:id/files` | |
100
+ | `upload_file` | `POST /workspaces/:id/files/binary` | |
98
101
  | `update_file` | `PUT /workspaces/:id/files/:fileId/content` | ✓ |
99
102
  | `delete_file` | `DELETE /workspaces/:id/files/:fileId` | ✓ |
100
103
 
104
+ `upload_file` stores a base64-encoded **binary** file (image, font, PDF, asset) in object storage rather than the Yjs text doc — the path for assets a persistent workspace serves at its preview URL / custom domain. `create_file`/`update_file` remain for UTF-8 text. Available in all profiles. Max 25 MiB.
105
+
101
106
  ### Writes: authoring (5 tools, interviewer profile only)
102
107
 
103
108
  | Tool | Writes | `destructive` |
@@ -120,6 +125,19 @@ Tools marked `destructive` carry the MCP `destructiveHint: true` annotation so h
120
125
 
121
126
  Each tool returns a structured timeline (per-file content checkpoints sampled across the session + chronological Run-button events) so the host LLM can write the prose summary, score, or follow-up questions itself. `score_against_rubric` also attaches the workspace's inline rubric + criteria; calls against a workspace with no applied problem return a friendly error pointing the user to `apply_problem_to_workspace`. `suggest_followup_questions` operates on the workspace's currently-active recording (last 5 minutes), and surfaces a clear error if no recording is in progress.
122
127
 
128
+ ### Completeness: file/folder + lifecycle (6 tools)
129
+
130
+ | Tool | Writes | Profile | `destructive` |
131
+ | --- | --- | --- | --- |
132
+ | `move_path` | `POST /workspaces/:id/move` | both | |
133
+ | `create_folder` | `POST /workspaces/:id/folders` | both | |
134
+ | `delete_folder` | `DELETE /workspaces/:id/folders/:folderId` | both | ✓ |
135
+ | `append_to_file` | `PATCH /workspaces/:id/files/:fileId/append` | both | |
136
+ | `delete_workspace` | `DELETE /workspaces/:id` | interviewer only | ✓ |
137
+ | `whoami` | `GET /auth/me` | both | |
138
+
139
+ `move_path` renames or moves any node (file or folder) to a full destination path, creating intermediate folders as needed; it rejects moving a folder into its own subtree. `create_folder` makes an empty folder (idempotent). `delete_folder` removes a folder and everything under it. `append_to_file` adds to the end of a file without re-sending its content. `delete_workspace` is interviewer-only and owner-gated by the API. `whoami` reports the identity + profile the server is running as.
140
+
123
141
  ## Layout
124
142
 
125
143
  ```
package/dist/client.d.ts CHANGED
@@ -19,5 +19,9 @@ export interface TypeletsClient {
19
19
  put<T>(path: string, body?: unknown): Promise<T>;
20
20
  patch<T>(path: string, body?: unknown): Promise<T>;
21
21
  delete<T>(path: string): Promise<T>;
22
+ /** Upload raw bytes (binary file) as an octet-stream body. Separate from
23
+ * the JSON helpers above because the body is not JSON and the mime type
24
+ * rides an extra header. */
25
+ uploadBinary<T>(workspaceId: string, filePath: string, bytes: Uint8Array, mimeType: string): Promise<T>;
22
26
  }
23
27
  export declare function createClient(env: Env): TypeletsClient;
package/dist/client.js CHANGED
@@ -47,12 +47,46 @@ export function createClient(env) {
47
47
  }
48
48
  return json;
49
49
  }
50
+ async function uploadBinary(workspaceId, filePath, bytes, mimeType) {
51
+ const url = `${env.apiUrl}/workspaces/${encodeURIComponent(workspaceId)}/files/binary` +
52
+ `?path=${encodeURIComponent(filePath)}`;
53
+ const res = await fetch(url, {
54
+ method: 'POST',
55
+ headers: {
56
+ accept: 'application/json',
57
+ authorization: `Bearer ${env.token}`,
58
+ 'content-type': 'application/octet-stream',
59
+ 'x-file-mime': mimeType,
60
+ },
61
+ body: bytes,
62
+ });
63
+ if (res.status === 204)
64
+ return undefined;
65
+ const text = await res.text();
66
+ let json = null;
67
+ if (text.length > 0) {
68
+ try {
69
+ json = JSON.parse(text);
70
+ }
71
+ catch {
72
+ json = text;
73
+ }
74
+ }
75
+ if (!res.ok) {
76
+ const message = json !== null && typeof json === 'object' && 'error' in json && typeof json.error === 'string'
77
+ ? json.error
78
+ : `Typelets API POST /workspaces/${workspaceId}/files/binary failed with ${res.status}`;
79
+ throw new TypeletsApiError(res.status, message, json);
80
+ }
81
+ return json;
82
+ }
50
83
  return {
51
84
  get: (path) => request('GET', path),
52
85
  post: (path, body) => request('POST', path, body),
53
86
  put: (path, body) => request('PUT', path, body),
54
87
  patch: (path, body) => request('PATCH', path, body),
55
88
  delete: (path) => request('DELETE', path),
89
+ uploadBinary: (workspaceId, filePath, bytes, mimeType) => uploadBinary(workspaceId, filePath, bytes, mimeType),
56
90
  };
57
91
  }
58
92
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAWA,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAEvB;IAEA;IAHlB,YACkB,MAAc,EAC9B,OAAe,EACC,IAAc;QAE9B,KAAK,CAAC,OAAO,CAAC,CAAC;QAJC,WAAM,GAAN,MAAM,CAAQ;QAEd,SAAI,GAAJ,IAAI,CAAU;QAG9B,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF;AAUD,MAAM,UAAU,YAAY,CAAC,GAAQ;IACnC,KAAK,UAAU,OAAO,CACpB,MAAmD,EACnD,IAAY,EACZ,IAAc;QAEd,MAAM,GAAG,GAAG,GAAG,GAAG,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC;QACnC,MAAM,OAAO,GAA2B;YACtC,MAAM,EAAE,kBAAkB;YAC1B,aAAa,EAAE,UAAU,GAAG,CAAC,KAAK,EAAE;SACrC,CAAC;QACF,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,CAAC,cAAc,CAAC,GAAG,kBAAkB,CAAC;QAErE,oEAAoE;QACpE,kEAAkE;QAClE,qBAAqB;QACrB,MAAM,IAAI,GAAgB,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;QAC9C,IAAI,IAAI,KAAK,SAAS;YAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACzD,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAEnC,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,SAAc,CAAC;QAE9C,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,IAAI,IAAI,GAAY,IAAI,CAAC;QACzB,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpB,IAAI,CAAC;gBACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC1B,CAAC;YAAC,MAAM,CAAC;gBACP,8DAA8D;gBAC9D,8DAA8D;gBAC9D,gEAAgE;gBAChE,IAAI,GAAG,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,OAAO,GACX,CAAC,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAO,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC;gBAC9F,CAAC,CAAC,IAAI,CAAC,KAAK;gBACZ,CAAC,CAAC,gBAAgB,MAAM,IAAI,IAAI,gBAAgB,GAAG,CAAC,MAAM,EAAE,CAAC;YACjE,MAAM,IAAI,gBAAgB,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;QACxD,CAAC;QAED,OAAO,IAAS,CAAC;IACnB,CAAC;IAED,OAAO;QACL,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC;QACnC,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC;QACjD,GAAG,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC;QAC/C,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC;QACnD,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC;KAC1C,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/env.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export interface Env {
2
2
  token: string;
3
3
  apiUrl: string;
4
- profile: 'interviewer' | 'candidate';
4
+ profile: 'interviewer' | 'candidate' | 'general';
5
5
  }
6
6
  export declare function readEnv(): Env;
package/dist/env.js CHANGED
@@ -21,12 +21,19 @@ const apiUrlSchema = z
21
21
  .url()
22
22
  .default('https://api.typelets.com');
23
23
  /**
24
- * Which tool surface to expose. `interviewer` (default) sees rubric +
25
- * hidden test content. `candidate` strips it out so an AI assistant
26
- * helping a candidate can not be fed the answer key. The profile is
27
- * fixed at start-up; the server refuses to switch it at runtime.
24
+ * Which tool surface to expose:
25
+ * - `interviewer` (default): full surface; sees rubric + hidden test content.
26
+ * - `candidate`: strips answer-key content and withholds workspace lifecycle
27
+ * + interview-authoring tools, so an AI assistant helping a candidate can
28
+ * not be fed the answer key or reshape the interview.
29
+ * - `general`: for using Typelets as a hosted dev/workspace product rather
30
+ * than for interviews — full authoring (workspace lifecycle + file/folder
31
+ * CRUD + reads) but none of the interview machinery.
32
+ * The profile is fixed at start-up; the server refuses to switch it at runtime.
28
33
  */
29
- const profileSchema = z.enum(['interviewer', 'candidate']).default('interviewer');
34
+ const profileSchema = z
35
+ .enum(['interviewer', 'candidate', 'general'])
36
+ .default('interviewer');
30
37
  export function readEnv() {
31
38
  const token = tokenSchema.parse(process.env.TYPELETS_TOKEN);
32
39
  const apiUrl = apiUrlSchema.parse(process.env.TYPELETS_API_URL);
package/dist/env.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;GAIG;AACH,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,kDAAkD,CAAC,CAAC;AAE3F;;;GAGG;AACH,MAAM,YAAY,GAAG,CAAC;KACnB,MAAM,EAAE;KACR,GAAG,EAAE;KACL,OAAO,CAAC,0BAA0B,CAAC,CAAC;AAEvC;;;;;GAKG;AACH,MAAM,aAAa,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;AAQlF,MAAM,UAAU,OAAO;IACrB,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAChE,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAClE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AACpC,CAAC"}
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;GAIG;AACH,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,kDAAkD,CAAC,CAAC;AAE3F;;;GAGG;AACH,MAAM,YAAY,GAAG,CAAC;KACnB,MAAM,EAAE;KACR,GAAG,EAAE;KACL,OAAO,CAAC,0BAA0B,CAAC,CAAC;AAEvC;;;;;;;;;;GAUG;AACH,MAAM,aAAa,GAAG,CAAC;KACpB,IAAI,CAAC,CAAC,aAAa,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;KAC7C,OAAO,CAAC,aAAa,CAAC,CAAC;AAQ1B,MAAM,UAAU,OAAO;IACrB,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAChE,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAClE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AACpC,CAAC"}
package/dist/index.js CHANGED
@@ -26,6 +26,7 @@ import { registerGetProblem } from './tools/get_problem.js';
26
26
  import { registerListRecordings } from './tools/list_recordings.js';
27
27
  import { registerListPendingInvites } from './tools/list_pending_invites.js';
28
28
  import { registerCreateFile } from './tools/create_file.js';
29
+ import { registerUploadFile } from './tools/upload_file.js';
29
30
  import { registerUpdateFile } from './tools/update_file.js';
30
31
  import { registerDeleteFile } from './tools/delete_file.js';
31
32
  import { registerCreateWorkspace } from './tools/create_workspace.js';
@@ -36,6 +37,12 @@ import { registerDeleteProblem } from './tools/delete_problem.js';
36
37
  import { registerSummarizeRecording } from './tools/summarize_recording.js';
37
38
  import { registerScoreAgainstRubric } from './tools/score_against_rubric.js';
38
39
  import { registerSuggestFollowupQuestions } from './tools/suggest_followup_questions.js';
40
+ import { registerMovePath } from './tools/move_path.js';
41
+ import { registerCreateFolder } from './tools/create_folder.js';
42
+ import { registerDeleteFolder } from './tools/delete_folder.js';
43
+ import { registerAppendToFile } from './tools/append_to_file.js';
44
+ import { registerDeleteWorkspace } from './tools/delete_workspace.js';
45
+ import { registerWhoami } from './tools/whoami.js';
39
46
  async function main() {
40
47
  const env = readEnv();
41
48
  const client = createClient(env);
@@ -60,6 +67,7 @@ async function main() {
60
67
  registerListPendingInvites(server, client, env);
61
68
  // Phase 2 write tools (profile-gated inside each register function).
62
69
  registerCreateFile(server, client, env);
70
+ registerUploadFile(server, client, env);
63
71
  registerUpdateFile(server, client, env);
64
72
  registerDeleteFile(server, client, env);
65
73
  registerCreateWorkspace(server, client, env);
@@ -71,6 +79,13 @@ async function main() {
71
79
  registerSummarizeRecording(server, client, env);
72
80
  registerScoreAgainstRubric(server, client, env);
73
81
  registerSuggestFollowupQuestions(server, client, env);
82
+ // Phase 2.2 completeness tools (delete_workspace is interviewer-only).
83
+ registerMovePath(server, client, env);
84
+ registerCreateFolder(server, client, env);
85
+ registerDeleteFolder(server, client, env);
86
+ registerAppendToFile(server, client, env);
87
+ registerDeleteWorkspace(server, client, env);
88
+ registerWhoami(server, client, env);
74
89
  const transport = new StdioServerTransport();
75
90
  await server.connect(transport);
76
91
  // Log to stderr (stdout is the MCP transport). Surfaces in the client's
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/profile.d.ts CHANGED
@@ -36,14 +36,17 @@ export interface ProblemDetailLike {
36
36
  solution?: Record<string, unknown>;
37
37
  }
38
38
  /**
39
- * Names of tools that the candidate profile MUST NOT register. The
39
+ * Names of tools the candidate profile MUST NOT register: every
40
+ * interview-authoring/intelligence tool plus workspace lifecycle. The
40
41
  * server skips registration for these when `env.profile === 'candidate'`,
41
- * so the candidate's host LLM never sees them in `listTools` and cannot
42
- * try to invoke them.
42
+ * so the candidate's host LLM never sees them in `listTools`.
43
+ *
44
+ * Kept as a named export for the existing gating tests and any callers that
45
+ * relied on it; it is the union of the two sets above.
43
46
  *
44
47
  * Per-file CRUD (create_file, update_file, delete_file) is allowed for
45
- * candidates: they have editor role inside their own interview
46
- * workspace and need to be able to modify their files.
48
+ * candidates: they have editor role inside their own interview workspace
49
+ * and need to be able to modify their files.
47
50
  */
48
51
  export declare const INTERVIEWER_ONLY_TOOLS: ReadonlySet<string>;
49
52
  export declare function toolAllowedForProfile(toolName: string, profile: Env['profile']): boolean;
package/dist/profile.js CHANGED
@@ -1,15 +1,15 @@
1
1
  /**
2
- * Names of tools that the candidate profile MUST NOT register. The
3
- * server skips registration for these when `env.profile === 'candidate'`,
4
- * so the candidate's host LLM never sees them in `listTools` and cannot
5
- * try to invoke them.
2
+ * Interview-specific tools: authoring problems, plus the session-intelligence
3
+ * tools that read a recorded interview (summaries, rubric scoring, follow-up
4
+ * suggestions). These only make sense for an interviewer running a hiring
5
+ * loop, so both the `candidate` and `general` profiles skip registering them.
6
6
  *
7
- * Per-file CRUD (create_file, update_file, delete_file) is allowed for
8
- * candidates: they have editor role inside their own interview
9
- * workspace and need to be able to modify their files.
7
+ * `general` is the profile for someone using Typelets as a hosted
8
+ * dev/workspace product rather than for interviews: they get full authoring
9
+ * (workspace lifecycle + file/folder CRUD + reads) but none of the
10
+ * interview machinery.
10
11
  */
11
- export const INTERVIEWER_ONLY_TOOLS = new Set([
12
- 'create_workspace',
12
+ const INTERVIEW_TOOLS = new Set([
13
13
  'apply_problem_to_workspace',
14
14
  'save_problem_to_library',
15
15
  'edit_problem',
@@ -18,9 +18,41 @@ export const INTERVIEWER_ONLY_TOOLS = new Set([
18
18
  'score_against_rubric',
19
19
  'suggest_followup_questions',
20
20
  ]);
21
+ /**
22
+ * Workspace lifecycle tools. An interviewer or a general (product) user can
23
+ * create and delete their own workspaces; a candidate works only inside the
24
+ * interview workspace they were invited to, so these are withheld from the
25
+ * candidate profile.
26
+ */
27
+ const WORKSPACE_LIFECYCLE_TOOLS = new Set([
28
+ 'create_workspace',
29
+ 'delete_workspace',
30
+ ]);
31
+ /**
32
+ * Names of tools the candidate profile MUST NOT register: every
33
+ * interview-authoring/intelligence tool plus workspace lifecycle. The
34
+ * server skips registration for these when `env.profile === 'candidate'`,
35
+ * so the candidate's host LLM never sees them in `listTools`.
36
+ *
37
+ * Kept as a named export for the existing gating tests and any callers that
38
+ * relied on it; it is the union of the two sets above.
39
+ *
40
+ * Per-file CRUD (create_file, update_file, delete_file) is allowed for
41
+ * candidates: they have editor role inside their own interview workspace
42
+ * and need to be able to modify their files.
43
+ */
44
+ export const INTERVIEWER_ONLY_TOOLS = new Set([
45
+ ...WORKSPACE_LIFECYCLE_TOOLS,
46
+ ...INTERVIEW_TOOLS,
47
+ ]);
21
48
  export function toolAllowedForProfile(toolName, profile) {
22
49
  if (profile === 'interviewer')
23
50
  return true;
51
+ // general: full authoring (workspace lifecycle + file CRUD + reads) but no
52
+ // interview tooling.
53
+ if (profile === 'general')
54
+ return !INTERVIEW_TOOLS.has(toolName);
55
+ // candidate: no interview tooling and no workspace lifecycle.
24
56
  return !INTERVIEWER_ONLY_TOOLS.has(toolName);
25
57
  }
26
58
  export function filterProblemForProfile(problem, env) {
@@ -1 +1 @@
1
- {"version":3,"file":"profile.js","sourceRoot":"","sources":["../src/profile.ts"],"names":[],"mappings":"AAgCA;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAwB,IAAI,GAAG,CAAC;IACjE,kBAAkB;IAClB,4BAA4B;IAC5B,yBAAyB;IACzB,cAAc;IACd,gBAAgB;IAChB,qBAAqB;IACrB,sBAAsB;IACtB,4BAA4B;CAC7B,CAAC,CAAC;AAEH,MAAM,UAAU,qBAAqB,CAAC,QAAgB,EAAE,OAAuB;IAC7E,IAAI,OAAO,KAAK,aAAa;QAAE,OAAO,IAAI,CAAC;IAC3C,OAAO,CAAC,sBAAsB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,OAAU,EACV,GAAQ;IAER,IAAI,GAAG,CAAC,OAAO,KAAK,aAAa;QAAE,OAAO,OAAO,CAAC;IAClD,MAAM,IAAI,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC;IAC5B,OAAO,IAAI,CAAC,MAAM,CAAC;IACnB,OAAO,IAAI,CAAC,QAAQ,CAAC;IACrB,OAAO,IAAI,CAAC,QAAQ,CAAC;IACrB,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"profile.js","sourceRoot":"","sources":["../src/profile.ts"],"names":[],"mappings":"AAgCA;;;;;;;;;;GAUG;AACH,MAAM,eAAe,GAAwB,IAAI,GAAG,CAAC;IACnD,4BAA4B;IAC5B,yBAAyB;IACzB,cAAc;IACd,gBAAgB;IAChB,qBAAqB;IACrB,sBAAsB;IACtB,4BAA4B;CAC7B,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,yBAAyB,GAAwB,IAAI,GAAG,CAAC;IAC7D,kBAAkB;IAClB,kBAAkB;CACnB,CAAC,CAAC;AAEH;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAwB,IAAI,GAAG,CAAC;IACjE,GAAG,yBAAyB;IAC5B,GAAG,eAAe;CACnB,CAAC,CAAC;AAEH,MAAM,UAAU,qBAAqB,CAAC,QAAgB,EAAE,OAAuB;IAC7E,IAAI,OAAO,KAAK,aAAa;QAAE,OAAO,IAAI,CAAC;IAC3C,2EAA2E;IAC3E,qBAAqB;IACrB,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,CAAC,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACjE,8DAA8D;IAC9D,OAAO,CAAC,sBAAsB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,OAAU,EACV,GAAQ;IAER,IAAI,GAAG,CAAC,OAAO,KAAK,aAAa;QAAE,OAAO,OAAO,CAAC;IAClD,MAAM,IAAI,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC;IAC5B,OAAO,IAAI,CAAC,MAAM,CAAC;IACnB,OAAO,IAAI,CAAC,QAAQ,CAAC;IACrB,OAAO,IAAI,CAAC,QAAQ,CAAC;IACrB,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * append_to_file: append text to the end of a file without re-sending the
3
+ * whole content. Both profiles.
4
+ */
5
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
6
+ import type { TypeletsClient } from '../client.js';
7
+ import type { Env } from '../env.js';
8
+ export declare function registerAppendToFile(server: McpServer, client: TypeletsClient, env: Env): void;
@@ -0,0 +1,26 @@
1
+ import { z } from 'zod';
2
+ import { toolAllowedForProfile } from '../profile.js';
3
+ import { ok, fail } from './_shared.js';
4
+ export function registerAppendToFile(server, client, env) {
5
+ if (!toolAllowedForProfile('append_to_file', env.profile))
6
+ return;
7
+ server.registerTool('append_to_file', {
8
+ title: 'Append to a file',
9
+ description: 'Append text to the end of an existing file without re-sending its full content. Get fileId from list_workspace_files. The file must already exist (use create_file otherwise).',
10
+ inputSchema: {
11
+ workspaceId: z.string().min(1).describe('The workspace id.'),
12
+ fileId: z.string().min(1).describe('The file id from list_workspace_files.'),
13
+ text: z.string().min(1).describe('Text to append at the end of the file.'),
14
+ },
15
+ annotations: { destructiveHint: false },
16
+ }, async ({ workspaceId, fileId, text }) => {
17
+ try {
18
+ const out = await client.patch(`/workspaces/${encodeURIComponent(workspaceId)}/files/${encodeURIComponent(fileId)}/append`, { text });
19
+ return ok(`Appended to file (${out.bytes} bytes total).`, out);
20
+ }
21
+ catch (err) {
22
+ return fail(err);
23
+ }
24
+ });
25
+ }
26
+ //# sourceMappingURL=append_to_file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"append_to_file.js","sourceRoot":"","sources":["../../src/tools/append_to_file.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAOxC,MAAM,UAAU,oBAAoB,CAAC,MAAiB,EAAE,MAAsB,EAAE,GAAQ;IACtF,IAAI,CAAC,qBAAqB,CAAC,gBAAgB,EAAE,GAAG,CAAC,OAAO,CAAC;QAAE,OAAO;IAElE,MAAM,CAAC,YAAY,CACjB,gBAAgB,EAChB;QACE,KAAK,EAAE,kBAAkB;QACzB,WAAW,EACT,gLAAgL;QAClL,WAAW,EAAE;YACX,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC;YAC5D,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,wCAAwC,CAAC;YAC5E,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,wCAAwC,CAAC;SAC3E;QACD,WAAW,EAAE,EAAE,eAAe,EAAE,KAAK,EAAE;KACxC,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE;QACtC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAC5B,eAAe,kBAAkB,CAAC,WAAW,CAAC,UAAU,kBAAkB,CAAC,MAAM,CAAC,SAAS,EAC3F,EAAE,IAAI,EAAE,CACT,CAAC;YACF,OAAO,EAAE,CAAC,qBAAqB,GAAG,CAAC,KAAK,gBAAgB,EAAE,GAAG,CAAC,CAAC;QACjE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * create_folder: create an empty folder (with intermediate folders) at a path.
3
+ * Idempotent if the folder already exists. Both profiles.
4
+ */
5
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
6
+ import type { TypeletsClient } from '../client.js';
7
+ import type { Env } from '../env.js';
8
+ export declare function registerCreateFolder(server: McpServer, client: TypeletsClient, env: Env): void;
@@ -0,0 +1,25 @@
1
+ import { z } from 'zod';
2
+ import { toolAllowedForProfile } from '../profile.js';
3
+ import { ok, fail } from './_shared.js';
4
+ export function registerCreateFolder(server, client, env) {
5
+ if (!toolAllowedForProfile('create_folder', env.profile))
6
+ return;
7
+ server.registerTool('create_folder', {
8
+ title: 'Create a folder',
9
+ description: 'Create an empty folder at a slash-separated path; intermediate folders are created as needed. Idempotent if the folder already exists. Errors if a file occupies the path.',
10
+ inputSchema: {
11
+ workspaceId: z.string().min(1).describe('The workspace id.'),
12
+ path: z.string().min(1).describe('Folder path, e.g. "src/lib".'),
13
+ },
14
+ annotations: { destructiveHint: false },
15
+ }, async ({ workspaceId, path }) => {
16
+ try {
17
+ const out = await client.post(`/workspaces/${encodeURIComponent(workspaceId)}/folders`, { path });
18
+ return ok(`Created folder ${out.path}.`, out);
19
+ }
20
+ catch (err) {
21
+ return fail(err);
22
+ }
23
+ });
24
+ }
25
+ //# sourceMappingURL=create_folder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create_folder.js","sourceRoot":"","sources":["../../src/tools/create_folder.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AASxC,MAAM,UAAU,oBAAoB,CAAC,MAAiB,EAAE,MAAsB,EAAE,GAAQ;IACtF,IAAI,CAAC,qBAAqB,CAAC,eAAe,EAAE,GAAG,CAAC,OAAO,CAAC;QAAE,OAAO;IAEjE,MAAM,CAAC,YAAY,CACjB,eAAe,EACf;QACE,KAAK,EAAE,iBAAiB;QACxB,WAAW,EACT,4KAA4K;QAC9K,WAAW,EAAE;YACX,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC;YAC5D,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,8BAA8B,CAAC;SACjE;QACD,WAAW,EAAE,EAAE,eAAe,EAAE,KAAK,EAAE;KACxC,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,EAAE;QAC9B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAC3B,eAAe,kBAAkB,CAAC,WAAW,CAAC,UAAU,EACxD,EAAE,IAAI,EAAE,CACT,CAAC;YACF,OAAO,EAAE,CAAC,kBAAkB,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,CAAC,CAAC;QAChD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * delete_folder: recursively delete a folder and everything under it.
3
+ * Destructive. Both profiles (editors manage their own tree).
4
+ */
5
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
6
+ import type { TypeletsClient } from '../client.js';
7
+ import type { Env } from '../env.js';
8
+ export declare function registerDeleteFolder(server: McpServer, client: TypeletsClient, env: Env): void;
@@ -0,0 +1,28 @@
1
+ import { z } from 'zod';
2
+ import { toolAllowedForProfile } from '../profile.js';
3
+ import { ok, fail } from './_shared.js';
4
+ export function registerDeleteFolder(server, client, env) {
5
+ if (!toolAllowedForProfile('delete_folder', env.profile))
6
+ return;
7
+ server.registerTool('delete_folder', {
8
+ title: 'Delete a folder (recursive)',
9
+ description: 'Permanently delete a folder and ALL files and subfolders inside it. Get folderId from list_workspace_files with includeFolders=true. This cannot be undone.',
10
+ inputSchema: {
11
+ workspaceId: z.string().min(1).describe('The workspace id.'),
12
+ folderId: z
13
+ .string()
14
+ .min(1)
15
+ .describe('The folder id from list_workspace_files (includeFolders=true).'),
16
+ },
17
+ annotations: { destructiveHint: true },
18
+ }, async ({ workspaceId, folderId }) => {
19
+ try {
20
+ const out = await client.delete(`/workspaces/${encodeURIComponent(workspaceId)}/folders/${encodeURIComponent(folderId)}`);
21
+ return ok(`Deleted folder and ${out.deleted} item(s).`, out);
22
+ }
23
+ catch (err) {
24
+ return fail(err);
25
+ }
26
+ });
27
+ }
28
+ //# sourceMappingURL=delete_folder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete_folder.js","sourceRoot":"","sources":["../../src/tools/delete_folder.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAMxC,MAAM,UAAU,oBAAoB,CAAC,MAAiB,EAAE,MAAsB,EAAE,GAAQ;IACtF,IAAI,CAAC,qBAAqB,CAAC,eAAe,EAAE,GAAG,CAAC,OAAO,CAAC;QAAE,OAAO;IAEjE,MAAM,CAAC,YAAY,CACjB,eAAe,EACf;QACE,KAAK,EAAE,6BAA6B;QACpC,WAAW,EACT,6JAA6J;QAC/J,WAAW,EAAE;YACX,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC;YAC5D,QAAQ,EAAE,CAAC;iBACR,MAAM,EAAE;iBACR,GAAG,CAAC,CAAC,CAAC;iBACN,QAAQ,CAAC,gEAAgE,CAAC;SAC9E;QACD,WAAW,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE;KACvC,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,EAAE;QAClC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,MAAM,CAC7B,eAAe,kBAAkB,CAAC,WAAW,CAAC,YAAY,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CACzF,CAAC;YACF,OAAO,EAAE,CAAC,sBAAsB,GAAG,CAAC,OAAO,WAAW,EAAE,GAAG,CAAC,CAAC;QAC/D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * delete_workspace: permanently delete a workspace. Interviewer-only and
3
+ * destructive. Wraps the existing owner-gated DELETE /workspaces/:id (the api
4
+ * returns 403 if the caller is not the owner).
5
+ */
6
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
7
+ import type { TypeletsClient } from '../client.js';
8
+ import type { Env } from '../env.js';
9
+ export declare function registerDeleteWorkspace(server: McpServer, client: TypeletsClient, env: Env): void;
@@ -0,0 +1,24 @@
1
+ import { z } from 'zod';
2
+ import { toolAllowedForProfile } from '../profile.js';
3
+ import { ok, fail } from './_shared.js';
4
+ export function registerDeleteWorkspace(server, client, env) {
5
+ if (!toolAllowedForProfile('delete_workspace', env.profile))
6
+ return;
7
+ server.registerTool('delete_workspace', {
8
+ title: 'Delete a workspace',
9
+ description: 'Permanently delete a workspace and all its files, recordings, and members. Only the workspace owner can do this. This cannot be undone.',
10
+ inputSchema: {
11
+ workspaceId: z.string().min(1).describe('The workspace id to permanently delete.'),
12
+ },
13
+ annotations: { destructiveHint: true },
14
+ }, async ({ workspaceId }) => {
15
+ try {
16
+ await client.delete(`/workspaces/${encodeURIComponent(workspaceId)}`);
17
+ return ok('Workspace deleted.', { workspaceId, deleted: true });
18
+ }
19
+ catch (err) {
20
+ return fail(err);
21
+ }
22
+ });
23
+ }
24
+ //# sourceMappingURL=delete_workspace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete_workspace.js","sourceRoot":"","sources":["../../src/tools/delete_workspace.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAExC,MAAM,UAAU,uBAAuB,CACrC,MAAiB,EACjB,MAAsB,EACtB,GAAQ;IAER,IAAI,CAAC,qBAAqB,CAAC,kBAAkB,EAAE,GAAG,CAAC,OAAO,CAAC;QAAE,OAAO;IAEpE,MAAM,CAAC,YAAY,CACjB,kBAAkB,EAClB;QACE,KAAK,EAAE,oBAAoB;QAC3B,WAAW,EACT,yIAAyI;QAC3I,WAAW,EAAE;YACX,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,yCAAyC,CAAC;SACnF;QACD,WAAW,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE;KACvC,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE;QACxB,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,MAAM,CAAO,eAAe,kBAAkB,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;YAC5E,OAAO,EAAE,CAAC,oBAAoB,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAClE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * move_path: rename or move a file/folder to a new path. The destination's
3
+ * parent folders are created as needed. Works on files and folders alike.
4
+ * Available to both profiles (editors manage their own tree).
5
+ */
6
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
7
+ import type { TypeletsClient } from '../client.js';
8
+ import type { Env } from '../env.js';
9
+ export declare function registerMovePath(server: McpServer, client: TypeletsClient, env: Env): void;
@@ -0,0 +1,29 @@
1
+ import { z } from 'zod';
2
+ import { toolAllowedForProfile } from '../profile.js';
3
+ import { ok, fail } from './_shared.js';
4
+ export function registerMovePath(server, client, env) {
5
+ if (!toolAllowedForProfile('move_path', env.profile))
6
+ return;
7
+ server.registerTool('move_path', {
8
+ title: 'Move or rename a file or folder',
9
+ description: 'Move or rename a node (file OR folder) to a new full path. Parent folders are created as needed. Get nodeId from list_workspace_files (use includeFolders for folders). Moving a folder into its own subtree is rejected.',
10
+ inputSchema: {
11
+ workspaceId: z.string().min(1).describe('The workspace id.'),
12
+ nodeId: z.string().min(1).describe('The file or folder id from list_workspace_files.'),
13
+ destinationPath: z
14
+ .string()
15
+ .min(1)
16
+ .describe('Full destination path, e.g. "src/lib/auth.ts".'),
17
+ },
18
+ annotations: { destructiveHint: false },
19
+ }, async ({ workspaceId, nodeId, destinationPath }) => {
20
+ try {
21
+ const out = await client.post(`/workspaces/${encodeURIComponent(workspaceId)}/files/move`, { nodeId, destinationPath });
22
+ return ok(`Moved to ${out.path}.`, out);
23
+ }
24
+ catch (err) {
25
+ return fail(err);
26
+ }
27
+ });
28
+ }
29
+ //# sourceMappingURL=move_path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"move_path.js","sourceRoot":"","sources":["../../src/tools/move_path.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AASxC,MAAM,UAAU,gBAAgB,CAAC,MAAiB,EAAE,MAAsB,EAAE,GAAQ;IAClF,IAAI,CAAC,qBAAqB,CAAC,WAAW,EAAE,GAAG,CAAC,OAAO,CAAC;QAAE,OAAO;IAE7D,MAAM,CAAC,YAAY,CACjB,WAAW,EACX;QACE,KAAK,EAAE,iCAAiC;QACxC,WAAW,EACT,2NAA2N;QAC7N,WAAW,EAAE;YACX,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC;YAC5D,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,kDAAkD,CAAC;YACtF,eAAe,EAAE,CAAC;iBACf,MAAM,EAAE;iBACR,GAAG,CAAC,CAAC,CAAC;iBACN,QAAQ,CAAC,gDAAgD,CAAC;SAC9D;QACD,WAAW,EAAE,EAAE,eAAe,EAAE,KAAK,EAAE;KACxC,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,eAAe,EAAE,EAAE,EAAE;QACjD,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAC3B,eAAe,kBAAkB,CAAC,WAAW,CAAC,aAAa,EAC3D,EAAE,MAAM,EAAE,eAAe,EAAE,CAC5B,CAAC;YACF,OAAO,EAAE,CAAC,YAAY,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * upload_file: upload a binary file (image/asset) into a workspace.
3
+ *
4
+ * MCP is a text transport, so the bytes arrive base64-encoded and are decoded
5
+ * here before being POSTed to the binary endpoint. Unlike create_file (which
6
+ * stores UTF-8 text in the Yjs doc), this stores raw bytes in object storage,
7
+ * which is how a persistent general workspace hosts images/assets served at
8
+ * its preview URL or custom domain.
9
+ *
10
+ * Available to every profile, same as the other file-CRUD tools: the API
11
+ * enforces workspace membership + role. It is not interview tooling, so it is
12
+ * not withheld from the candidate or general profiles.
13
+ */
14
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
15
+ import type { TypeletsClient } from '../client.js';
16
+ import type { Env } from '../env.js';
17
+ export declare function registerUploadFile(server: McpServer, client: TypeletsClient, env: Env): void;
@@ -0,0 +1,72 @@
1
+ import { z } from 'zod';
2
+ import { toolAllowedForProfile } from '../profile.js';
3
+ import { ok, fail } from './_shared.js';
4
+ /** Best-effort mime type from a path extension; the server re-validates. */
5
+ const EXT_MIME = {
6
+ png: 'image/png',
7
+ jpg: 'image/jpeg',
8
+ jpeg: 'image/jpeg',
9
+ gif: 'image/gif',
10
+ webp: 'image/webp',
11
+ avif: 'image/avif',
12
+ svg: 'image/svg+xml',
13
+ bmp: 'image/bmp',
14
+ ico: 'image/x-icon',
15
+ pdf: 'application/pdf',
16
+ woff: 'font/woff',
17
+ woff2: 'font/woff2',
18
+ ttf: 'font/ttf',
19
+ otf: 'font/otf',
20
+ mp3: 'audio/mpeg',
21
+ wav: 'audio/wav',
22
+ mp4: 'video/mp4',
23
+ webm: 'video/webm',
24
+ zip: 'application/zip',
25
+ wasm: 'application/wasm',
26
+ };
27
+ function mimeFor(path, explicit) {
28
+ if (typeof explicit === 'string' && explicit.length > 0)
29
+ return explicit;
30
+ const ext = path.split('.').pop()?.toLowerCase() ?? '';
31
+ return EXT_MIME[ext] ?? 'application/octet-stream';
32
+ }
33
+ export function registerUploadFile(server, client, env) {
34
+ // Profile gate: keep the string in sync with profile.ts.
35
+ if (!toolAllowedForProfile('upload_file', env.profile))
36
+ return;
37
+ server.registerTool('upload_file', {
38
+ title: 'Upload a binary file to a workspace',
39
+ description: 'Upload a binary file (image, font, PDF, or other asset) to a slash-separated path in a workspace. The content must be base64-encoded; intermediate folders are created as needed. Use create_file for UTF-8 text. On a persistent workspace the uploaded asset is served at its preview URL / custom domain. Errors: 409 if a file already exists at the path; 413 if the file exceeds 25 MiB.',
40
+ inputSchema: {
41
+ workspaceId: z.string().min(1).describe('The workspace id from list_workspaces.'),
42
+ path: z
43
+ .string()
44
+ .min(1)
45
+ .describe('Slash-separated path from the workspace root (e.g. "assets/logo.png"). Cannot contain ".." segments.'),
46
+ contentBase64: z.string().min(1).describe('The file bytes, base64-encoded.'),
47
+ mimeType: z
48
+ .string()
49
+ .optional()
50
+ .describe('MIME type, e.g. "image/png". Inferred from the path extension when omitted.'),
51
+ },
52
+ }, async ({ workspaceId, path, contentBase64, mimeType }) => {
53
+ let bytes;
54
+ try {
55
+ bytes = new Uint8Array(Buffer.from(contentBase64, 'base64'));
56
+ }
57
+ catch {
58
+ return fail(new Error('contentBase64 is not valid base64.'));
59
+ }
60
+ if (bytes.length === 0) {
61
+ return fail(new Error('Decoded content is empty.'));
62
+ }
63
+ try {
64
+ const result = await client.uploadBinary(workspaceId, path, bytes, mimeFor(path, mimeType));
65
+ return ok(`Uploaded ${result.path} (id=${result.id}, ${result.mimeType}, ${result.sizeBytes} bytes).`, { file: result });
66
+ }
67
+ catch (err) {
68
+ return fail(err);
69
+ }
70
+ });
71
+ }
72
+ //# sourceMappingURL=upload_file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload_file.js","sourceRoot":"","sources":["../../src/tools/upload_file.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * whoami: return the authenticated caller's identity. Wraps GET /auth/me so
3
+ * the host LLM can confirm which account + profile it's operating as. Both
4
+ * profiles.
5
+ */
6
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
7
+ import type { TypeletsClient } from '../client.js';
8
+ import type { Env } from '../env.js';
9
+ export declare function registerWhoami(server: McpServer, client: TypeletsClient, env: Env): void;
@@ -0,0 +1,25 @@
1
+ import { toolAllowedForProfile } from '../profile.js';
2
+ import { ok, fail } from './_shared.js';
3
+ export function registerWhoami(server, client, env) {
4
+ if (!toolAllowedForProfile('whoami', env.profile))
5
+ return;
6
+ server.registerTool('whoami', {
7
+ title: 'Who am I',
8
+ description: 'Return the authenticated caller identity (id, email, display name) for the PAT this server is using, plus the active profile. Use to confirm which account you are operating as.',
9
+ inputSchema: {},
10
+ annotations: { destructiveHint: false },
11
+ }, async () => {
12
+ try {
13
+ const me = await client.get('/auth/me');
14
+ const who = me.displayName ?? me.email ?? me.id;
15
+ return ok(`Authenticated as ${who} (profile: ${env.profile}).`, {
16
+ ...me,
17
+ profile: env.profile,
18
+ });
19
+ }
20
+ catch (err) {
21
+ return fail(err);
22
+ }
23
+ });
24
+ }
25
+ //# sourceMappingURL=whoami.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../src/tools/whoami.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AASxC,MAAM,UAAU,cAAc,CAAC,MAAiB,EAAE,MAAsB,EAAE,GAAQ;IAChF,IAAI,CAAC,qBAAqB,CAAC,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC;QAAE,OAAO;IAE1D,MAAM,CAAC,YAAY,CACjB,QAAQ,EACR;QACE,KAAK,EAAE,UAAU;QACjB,WAAW,EACT,kLAAkL;QACpL,WAAW,EAAE,EAAE;QACf,WAAW,EAAE,EAAE,eAAe,EAAE,KAAK,EAAE;KACxC,EACD,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,GAAG,CAAa,UAAU,CAAC,CAAC;YACpD,MAAM,GAAG,GAAG,EAAE,CAAC,WAAW,IAAI,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC;YAChD,OAAO,EAAE,CAAC,oBAAoB,GAAG,cAAc,GAAG,CAAC,OAAO,IAAI,EAAE;gBAC9D,GAAG,EAAE;gBACL,OAAO,EAAE,GAAG,CAAC,OAAO;aACrB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typelets/mcp",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Model Context Protocol server for Typelets. Wraps the Typelets API as tools an MCP-capable LLM client can call.",
5
5
  "type": "module",
6
6
  "bin": {