@typelets/mcp 0.2.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/LICENSE +21 -0
- package/README.md +148 -0
- package/dist/client.d.ts +23 -0
- package/dist/client.js +58 -0
- package/dist/client.js.map +1 -0
- package/dist/env.d.ts +6 -0
- package/dist/env.js +36 -0
- package/dist/env.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +77 -0
- package/dist/index.js.map +1 -0
- package/dist/profile.d.ts +50 -0
- package/dist/profile.js +35 -0
- package/dist/profile.js.map +1 -0
- package/dist/tools/_shared.d.ts +17 -0
- package/dist/tools/_shared.js +55 -0
- package/dist/tools/_shared.js.map +1 -0
- package/dist/tools/apply_problem_to_workspace.d.ts +12 -0
- package/dist/tools/apply_problem_to_workspace.js +31 -0
- package/dist/tools/apply_problem_to_workspace.js.map +1 -0
- package/dist/tools/create_file.d.ts +11 -0
- package/dist/tools/create_file.js +29 -0
- package/dist/tools/create_file.js.map +1 -0
- package/dist/tools/create_workspace.d.ts +11 -0
- package/dist/tools/create_workspace.js +33 -0
- package/dist/tools/create_workspace.js.map +1 -0
- package/dist/tools/delete_file.d.ts +12 -0
- package/dist/tools/delete_file.js +26 -0
- package/dist/tools/delete_file.js.map +1 -0
- package/dist/tools/delete_problem.d.ts +11 -0
- package/dist/tools/delete_problem.js +29 -0
- package/dist/tools/delete_problem.js.map +1 -0
- package/dist/tools/edit_problem.d.ts +11 -0
- package/dist/tools/edit_problem.js +87 -0
- package/dist/tools/edit_problem.js.map +1 -0
- package/dist/tools/get_problem.d.ts +13 -0
- package/dist/tools/get_problem.js +27 -0
- package/dist/tools/get_problem.js.map +1 -0
- package/dist/tools/get_workspace.d.ts +12 -0
- package/dist/tools/get_workspace.js +23 -0
- package/dist/tools/get_workspace.js.map +1 -0
- package/dist/tools/list_pending_invites.d.ts +12 -0
- package/dist/tools/list_pending_invites.js +39 -0
- package/dist/tools/list_pending_invites.js.map +1 -0
- package/dist/tools/list_problems.d.ts +15 -0
- package/dist/tools/list_problems.js +38 -0
- package/dist/tools/list_problems.js.map +1 -0
- package/dist/tools/list_recordings.d.ts +12 -0
- package/dist/tools/list_recordings.js +20 -0
- package/dist/tools/list_recordings.js.map +1 -0
- package/dist/tools/list_workspace_files.d.ts +15 -0
- package/dist/tools/list_workspace_files.js +25 -0
- package/dist/tools/list_workspace_files.js.map +1 -0
- package/dist/tools/list_workspaces.d.ts +11 -0
- package/dist/tools/list_workspaces.js +20 -0
- package/dist/tools/list_workspaces.js.map +1 -0
- package/dist/tools/read_workspace_file.d.ts +16 -0
- package/dist/tools/read_workspace_file.js +24 -0
- package/dist/tools/read_workspace_file.js.map +1 -0
- package/dist/tools/save_problem_to_library.d.ts +11 -0
- package/dist/tools/save_problem_to_library.js +83 -0
- package/dist/tools/save_problem_to_library.js.map +1 -0
- package/dist/tools/update_file.d.ts +12 -0
- package/dist/tools/update_file.js +27 -0
- package/dist/tools/update_file.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ok, fail } from './_shared.js';
|
|
2
|
+
export function registerListWorkspaces(server, client, _env) {
|
|
3
|
+
server.registerTool('list_workspaces', {
|
|
4
|
+
title: 'List workspaces',
|
|
5
|
+
description: 'Return every Typelets workspace the caller can access, with role + mode + sharing scope. Use this first to discover workspace ids.',
|
|
6
|
+
inputSchema: {},
|
|
7
|
+
}, async () => {
|
|
8
|
+
try {
|
|
9
|
+
const { workspaces } = await client.get('/workspaces');
|
|
10
|
+
const summary = workspaces.length === 0
|
|
11
|
+
? 'The caller has no workspaces.'
|
|
12
|
+
: `Found ${workspaces.length} workspace${workspaces.length === 1 ? '' : 's'}.`;
|
|
13
|
+
return ok(summary, { workspaces });
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
return fail(err);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=list_workspaces.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list_workspaces.js","sourceRoot":"","sources":["../../src/tools/list_workspaces.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAexC,MAAM,UAAU,sBAAsB,CACpC,MAAiB,EACjB,MAAsB,EACtB,IAAS;IAET,MAAM,CAAC,YAAY,CACjB,iBAAiB,EACjB;QACE,KAAK,EAAE,iBAAiB;QACxB,WAAW,EACT,oIAAoI;QACtI,WAAW,EAAE,EAAE;KAChB,EACD,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,GAAG,CAAyB,aAAa,CAAC,CAAC;YAC/E,MAAM,OAAO,GACX,UAAU,CAAC,MAAM,KAAK,CAAC;gBACrB,CAAC,CAAC,+BAA+B;gBACjC,CAAC,CAAC,SAAS,UAAU,CAAC,MAAM,aAAa,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;YACnF,OAAO,EAAE,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;QACrC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* read_workspace_file: return the contents of a single workspace file.
|
|
3
|
+
*
|
|
4
|
+
* Backed by `GET /workspaces/:id/files/:fileId/content`. The Typelets
|
|
5
|
+
* API returns the materialised UTF-8 content of the file at HEAD;
|
|
6
|
+
* binary files are rejected with a 415 (the MCP transport is text-only
|
|
7
|
+
* and the model can't reason about raw bytes anyway).
|
|
8
|
+
*
|
|
9
|
+
* Long files are truncated server-side; the response carries a
|
|
10
|
+
* `truncated: true` flag in that case so the model can ask for a
|
|
11
|
+
* follow-up range if needed.
|
|
12
|
+
*/
|
|
13
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
14
|
+
import type { TypeletsClient } from '../client.js';
|
|
15
|
+
import type { Env } from '../env.js';
|
|
16
|
+
export declare function registerReadWorkspaceFile(server: McpServer, client: TypeletsClient, _env: Env): void;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ok, fail } from './_shared.js';
|
|
3
|
+
export function registerReadWorkspaceFile(server, client, _env) {
|
|
4
|
+
server.registerTool('read_workspace_file', {
|
|
5
|
+
title: 'Read workspace file',
|
|
6
|
+
description: 'Fetch the UTF-8 contents of a single file in a workspace. Use list_workspace_files first to obtain the fileId. Binary files are rejected; long files may be truncated.',
|
|
7
|
+
inputSchema: {
|
|
8
|
+
workspaceId: z.string().min(1).describe('The workspace id.'),
|
|
9
|
+
fileId: z.string().min(1).describe('The file id from list_workspace_files.'),
|
|
10
|
+
},
|
|
11
|
+
}, async ({ workspaceId, fileId }) => {
|
|
12
|
+
try {
|
|
13
|
+
const payload = await client.get(`/workspaces/${encodeURIComponent(workspaceId)}/files/${encodeURIComponent(fileId)}/content`);
|
|
14
|
+
const summary = payload.truncated
|
|
15
|
+
? `Read ${payload.path} (${payload.bytes} bytes, TRUNCATED).`
|
|
16
|
+
: `Read ${payload.path} (${payload.bytes} bytes).`;
|
|
17
|
+
return ok(summary, payload);
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
return fail(err);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=read_workspace_file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read_workspace_file.js","sourceRoot":"","sources":["../../src/tools/read_workspace_file.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AASxC,MAAM,UAAU,yBAAyB,CACvC,MAAiB,EACjB,MAAsB,EACtB,IAAS;IAET,MAAM,CAAC,YAAY,CACjB,qBAAqB,EACrB;QACE,KAAK,EAAE,qBAAqB;QAC5B,WAAW,EACT,wKAAwK;QAC1K,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;SAC7E;KACF,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE;QAChC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,GAAG,CAC9B,eAAe,kBAAkB,CAAC,WAAW,CAAC,UAAU,kBAAkB,CAAC,MAAM,CAAC,UAAU,CAC7F,CAAC;YACF,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS;gBAC/B,CAAC,CAAC,QAAQ,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,KAAK,qBAAqB;gBAC7D,CAAC,CAAC,QAAQ,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,KAAK,UAAU,CAAC;YACrD,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC9B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* save_problem_to_library: create a new problem in the library.
|
|
3
|
+
*
|
|
4
|
+
* Interviewer-only. The caller becomes the problem's owner and is the
|
|
5
|
+
* only one who can later edit or delete it (org admins of the owning
|
|
6
|
+
* Organization can also edit/delete org-visibility problems).
|
|
7
|
+
*/
|
|
8
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
9
|
+
import type { TypeletsClient } from '../client.js';
|
|
10
|
+
import type { Env } from '../env.js';
|
|
11
|
+
export declare function registerSaveProblemToLibrary(server: McpServer, client: TypeletsClient, env: Env): void;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { toolAllowedForProfile } from '../profile.js';
|
|
3
|
+
import { ok, fail } from './_shared.js';
|
|
4
|
+
const criterionSchema = z.object({
|
|
5
|
+
name: z.string().trim().min(1).max(120),
|
|
6
|
+
description: z.string().max(2000),
|
|
7
|
+
});
|
|
8
|
+
const stdinTestCaseSchema = z.object({
|
|
9
|
+
kind: z.literal('stdin').optional(),
|
|
10
|
+
name: z.string().trim().min(1).max(120),
|
|
11
|
+
stdin: z.string().max(20000),
|
|
12
|
+
expectedStdout: z.string().max(20000),
|
|
13
|
+
visible: z.boolean().default(true),
|
|
14
|
+
});
|
|
15
|
+
const frameworkTestCaseSchema = z.object({
|
|
16
|
+
kind: z.literal('framework'),
|
|
17
|
+
name: z.string().trim().min(1).max(120),
|
|
18
|
+
framework: z.enum([
|
|
19
|
+
'go', 'pytest', 'jest', 'vitest', 'rspec',
|
|
20
|
+
'minitest', 'npm-test', 'rails', 'phpunit', 'other',
|
|
21
|
+
]),
|
|
22
|
+
command: z.string().min(1).max(4000),
|
|
23
|
+
visible: z.boolean().default(true),
|
|
24
|
+
});
|
|
25
|
+
const testCaseSchema = z.union([frameworkTestCaseSchema, stdinTestCaseSchema]);
|
|
26
|
+
const problemFileSchema = z.object({
|
|
27
|
+
name: z.string().trim().min(1).max(512).describe('Slash-separated path from workspace root, e.g. "src/lib/foo.ts".'),
|
|
28
|
+
content: z.string().max(1_048_576),
|
|
29
|
+
});
|
|
30
|
+
const categoryEnum = z.enum([
|
|
31
|
+
'arrays_strings',
|
|
32
|
+
'hash_tables',
|
|
33
|
+
'linked_lists',
|
|
34
|
+
'stacks_queues',
|
|
35
|
+
'trees',
|
|
36
|
+
'graphs',
|
|
37
|
+
'recursion_dp',
|
|
38
|
+
'sorting_searching',
|
|
39
|
+
'math_bigo',
|
|
40
|
+
'design',
|
|
41
|
+
'ai',
|
|
42
|
+
'data',
|
|
43
|
+
'frontend',
|
|
44
|
+
'backend',
|
|
45
|
+
'systems',
|
|
46
|
+
'sql',
|
|
47
|
+
'other',
|
|
48
|
+
]);
|
|
49
|
+
export function registerSaveProblemToLibrary(server, client, env) {
|
|
50
|
+
// Profile gate: keep the string in sync with INTERVIEWER_ONLY_TOOLS in ../profile.ts.
|
|
51
|
+
if (!toolAllowedForProfile('save_problem_to_library', env.profile))
|
|
52
|
+
return;
|
|
53
|
+
server.registerTool('save_problem_to_library', {
|
|
54
|
+
title: 'Create a new problem in the library',
|
|
55
|
+
description: 'Create a new problem in the Typelets problem library. The caller becomes the problem\'s owner. ' +
|
|
56
|
+
'Returns the new problem including its id and slug. ' +
|
|
57
|
+
'Errors: 409 if a problem with that slug already exists (choose a different slug).',
|
|
58
|
+
inputSchema: {
|
|
59
|
+
slug: z.string().trim().min(1).max(120).regex(/^[a-z0-9-]+$/, 'Slug must be lowercase letters, numbers, and dashes.').describe('URL-safe identifier, e.g. "two-sum". Must be unique across the library.'),
|
|
60
|
+
title: z.string().trim().min(1).max(200).describe('Human-readable problem title, e.g. "Two Sum".'),
|
|
61
|
+
difficulty: z.enum(['easy', 'medium', 'hard']).default('medium').describe('Problem difficulty. Defaults to "medium".'),
|
|
62
|
+
prompt: z.string().min(1).max(20000).describe('The problem statement shown to candidates. Markdown supported.'),
|
|
63
|
+
rubric: z.string().max(20000).nullable().optional().describe('Interviewer-only scoring rubric. Not visible to candidates. Markdown supported.'),
|
|
64
|
+
criteria: z.array(criterionSchema).max(20).default([]).describe('Structured scoring criteria (name + description pairs). Up to 20.'),
|
|
65
|
+
tests: z.array(testCaseSchema).max(40).default([]).describe('Test cases: either stdin/expectedStdout or framework-exec. Up to 40.'),
|
|
66
|
+
starters: z.record(z.string(), z.string()).default({}).describe('Legacy single-file starter map (filename → content). Prefer starterFiles for new problems.'),
|
|
67
|
+
starterFiles: z.array(problemFileSchema).max(5000).default([]).describe('Starter file tree materialized into the workspace when the problem is applied. Up to 5000 files.'),
|
|
68
|
+
solutionFiles: z.array(problemFileSchema).max(5000).default([]).describe('Reference solution files (interviewer-only, never shown to candidates). Up to 5000 files.'),
|
|
69
|
+
testFiles: z.array(problemFileSchema).max(5000).default([]).describe('Test framework files materialized into the workspace alongside starter files. Up to 5000 files.'),
|
|
70
|
+
tags: z.array(z.string().trim().min(1).max(40)).max(20).default([]).describe('Search tags, e.g. ["arrays", "hash-map"]. Up to 20, each max 40 chars.'),
|
|
71
|
+
category: categoryEnum.default('other').describe('Problem category for filtering.'),
|
|
72
|
+
},
|
|
73
|
+
}, async (input) => {
|
|
74
|
+
try {
|
|
75
|
+
const result = await client.post('/problems', input);
|
|
76
|
+
return ok(`Created problem "${result.problem.title}" (id=${result.problem.id}, slug=${result.problem.slug}).`, { problem: result.problem });
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
return fail(err);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=save_problem_to_library.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"save_problem_to_library.js","sourceRoot":"","sources":["../../src/tools/save_problem_to_library.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* update_file: replace the entire contents of an existing workspace file.
|
|
3
|
+
*
|
|
4
|
+
* Available to both interviewer and candidate profiles. Marked destructive
|
|
5
|
+
* because the overwrite is irreversible from the MCP server's perspective.
|
|
6
|
+
* a co-editor currently open on the file sees the change live and their
|
|
7
|
+
* cursor position may be displaced.
|
|
8
|
+
*/
|
|
9
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
10
|
+
import type { TypeletsClient } from '../client.js';
|
|
11
|
+
import type { Env } from '../env.js';
|
|
12
|
+
export declare function registerUpdateFile(server: McpServer, client: TypeletsClient, env: Env): void;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { toolAllowedForProfile } from '../profile.js';
|
|
3
|
+
import { ok, fail } from './_shared.js';
|
|
4
|
+
export function registerUpdateFile(server, client, env) {
|
|
5
|
+
// Profile gate: keep the string in sync with INTERVIEWER_ONLY_TOOLS in ../profile.ts.
|
|
6
|
+
if (!toolAllowedForProfile('update_file', env.profile))
|
|
7
|
+
return;
|
|
8
|
+
server.registerTool('update_file', {
|
|
9
|
+
title: "Replace a file's contents",
|
|
10
|
+
description: "Replace the entire contents of a file with new UTF-8 text. Use create_file if the file does not exist yet. This overwrites wholesale: any co-editor currently editing the file sees the change live and their cursor may move; their in-flight edits are NOT preserved. Returns the new byte count. Errors: 404 if the fileId does not exist in the workspace; 413 if content exceeds 1 MiB.",
|
|
11
|
+
inputSchema: {
|
|
12
|
+
workspaceId: z.string().min(1).describe('The workspace id from list_workspaces.'),
|
|
13
|
+
fileId: z.string().min(1).describe('The file id from list_workspace_files.'),
|
|
14
|
+
content: z.string().describe('Replacement UTF-8 content. Wholesale overwrite; no diff/patch semantics.'),
|
|
15
|
+
},
|
|
16
|
+
annotations: { destructiveHint: true },
|
|
17
|
+
}, async ({ workspaceId, fileId, content }) => {
|
|
18
|
+
try {
|
|
19
|
+
const result = await client.put(`/workspaces/${encodeURIComponent(workspaceId)}/files/${encodeURIComponent(fileId)}/content`, { content });
|
|
20
|
+
return ok(`Updated file ${result.path} (${result.bytes} bytes).`, { file: result });
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
return fail(err);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=update_file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update_file.js","sourceRoot":"","sources":["../../src/tools/update_file.ts"],"names":[],"mappings":"AASA,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;AAQxC,MAAM,UAAU,kBAAkB,CAAC,MAAiB,EAAE,MAAsB,EAAE,GAAQ;IACpF,sFAAsF;IACtF,IAAI,CAAC,qBAAqB,CAAC,aAAa,EAAE,GAAG,CAAC,OAAO,CAAC;QAAE,OAAO;IAE/D,MAAM,CAAC,YAAY,CACjB,aAAa,EACb;QACE,KAAK,EAAE,2BAA2B;QAClC,WAAW,EACT,8XAA8X;QAChY,WAAW,EAAE;YACX,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,wCAAwC,CAAC;YACjF,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,wCAAwC,CAAC;YAC5E,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0EAA0E,CAAC;SACzG;QACD,WAAW,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE;KACvC,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;QACzC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,GAAG,CAC7B,eAAe,kBAAkB,CAAC,WAAW,CAAC,UAAU,kBAAkB,CAAC,MAAM,CAAC,UAAU,EAC5F,EAAE,OAAO,EAAE,CACZ,CAAC;YACF,OAAO,EAAE,CAAC,gBAAgB,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,KAAK,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QACtF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@typelets/mcp",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Model Context Protocol server for Typelets. Wraps the Typelets API as tools an MCP-capable LLM client can call.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"typelets-mcp": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
15
|
+
"keywords": [
|
|
16
|
+
"mcp",
|
|
17
|
+
"model-context-protocol",
|
|
18
|
+
"typelets",
|
|
19
|
+
"interviews",
|
|
20
|
+
"ai-tools"
|
|
21
|
+
],
|
|
22
|
+
"homepage": "https://github.com/batalabs/typelets-mcp#readme",
|
|
23
|
+
"bugs": "https://github.com/batalabs/typelets-mcp/issues",
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "https://github.com/batalabs/typelets-mcp.git"
|
|
27
|
+
},
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"author": "Typelets",
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=20"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
35
|
+
"zod": "^3.23.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/node": "^22.0.0",
|
|
39
|
+
"eslint": "^9.0.0",
|
|
40
|
+
"tsx": "^4.0.0",
|
|
41
|
+
"typescript": "^5.5.0"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "tsc",
|
|
45
|
+
"dev": "tsc --watch",
|
|
46
|
+
"typecheck": "tsc --noEmit",
|
|
47
|
+
"test": "node --test --import tsx tests/**/*.test.ts",
|
|
48
|
+
"lint": "eslint src tests --max-warnings=0"
|
|
49
|
+
}
|
|
50
|
+
}
|