@typelets/mcp 0.4.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 +11 -6
- package/dist/client.d.ts +4 -0
- package/dist/client.js +34 -0
- package/dist/client.js.map +1 -1
- package/dist/env.d.ts +1 -1
- package/dist/env.js +12 -5
- package/dist/env.js.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/profile.d.ts +8 -5
- package/dist/profile.js +40 -9
- package/dist/profile.js.map +1 -1
- package/dist/tools/upload_file.d.ts +17 -0
- package/dist/tools/upload_file.js +72 -0
- package/dist/tools/upload_file.js.map +1 -0
- package/package.json +1 -1
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
|
-
##
|
|
31
|
+
## Profiles
|
|
32
32
|
|
|
33
|
-
The server ships
|
|
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
|
-
- **`
|
|
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
|
|
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
|
-
- `
|
|
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
|
-
|
|
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` |
|
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
|
package/dist/client.js.map
CHANGED
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/env.d.ts
CHANGED
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
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
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
|
|
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
|
|
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';
|
|
@@ -66,6 +67,7 @@ async function main() {
|
|
|
66
67
|
registerListPendingInvites(server, client, env);
|
|
67
68
|
// Phase 2 write tools (profile-gated inside each register function).
|
|
68
69
|
registerCreateFile(server, client, env);
|
|
70
|
+
registerUploadFile(server, client, env);
|
|
69
71
|
registerUpdateFile(server, client, env);
|
|
70
72
|
registerDeleteFile(server, client, env);
|
|
71
73
|
registerCreateWorkspace(server, client, env);
|
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
|
|
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
|
|
42
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* workspace
|
|
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
|
-
|
|
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',
|
|
@@ -17,11 +17,42 @@ export const INTERVIEWER_ONLY_TOOLS = new Set([
|
|
|
17
17
|
'summarize_recording',
|
|
18
18
|
'score_against_rubric',
|
|
19
19
|
'suggest_followup_questions',
|
|
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',
|
|
20
29
|
'delete_workspace',
|
|
21
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
|
+
]);
|
|
22
48
|
export function toolAllowedForProfile(toolName, profile) {
|
|
23
49
|
if (profile === 'interviewer')
|
|
24
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.
|
|
25
56
|
return !INTERVIEWER_ONLY_TOOLS.has(toolName);
|
|
26
57
|
}
|
|
27
58
|
export function filterProblemForProfile(problem, env) {
|
package/dist/profile.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profile.js","sourceRoot":"","sources":["../src/profile.ts"],"names":[],"mappings":"AAgCA
|
|
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,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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"}
|