@tankpkg/mcp-server 0.4.2 → 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.
Files changed (63) hide show
  1. package/README.md +41 -33
  2. package/dist/index.js +24 -0
  3. package/dist/index.js.map +1 -1
  4. package/dist/lib/api-client.d.ts +6 -5
  5. package/dist/lib/api-client.d.ts.map +1 -1
  6. package/dist/lib/api-client.js +6 -6
  7. package/dist/lib/api-client.js.map +1 -1
  8. package/dist/lib/packer.d.ts +20 -0
  9. package/dist/lib/packer.d.ts.map +1 -1
  10. package/dist/lib/packer.js +85 -0
  11. package/dist/lib/packer.js.map +1 -1
  12. package/dist/tools/audit-skill.d.ts +3 -0
  13. package/dist/tools/audit-skill.d.ts.map +1 -0
  14. package/dist/tools/audit-skill.js +213 -0
  15. package/dist/tools/audit-skill.js.map +1 -0
  16. package/dist/tools/doctor.d.ts +3 -0
  17. package/dist/tools/doctor.d.ts.map +1 -0
  18. package/dist/tools/doctor.js +158 -0
  19. package/dist/tools/doctor.js.map +1 -0
  20. package/dist/tools/init-skill.d.ts +3 -0
  21. package/dist/tools/init-skill.d.ts.map +1 -0
  22. package/dist/tools/init-skill.js +72 -0
  23. package/dist/tools/init-skill.js.map +1 -0
  24. package/dist/tools/install-skill.d.ts +3 -0
  25. package/dist/tools/install-skill.d.ts.map +1 -0
  26. package/dist/tools/install-skill.js +206 -0
  27. package/dist/tools/install-skill.js.map +1 -0
  28. package/dist/tools/link-skill.d.ts +3 -0
  29. package/dist/tools/link-skill.d.ts.map +1 -0
  30. package/dist/tools/link-skill.js +81 -0
  31. package/dist/tools/link-skill.js.map +1 -0
  32. package/dist/tools/logout.d.ts +3 -0
  33. package/dist/tools/logout.d.ts.map +1 -0
  34. package/dist/tools/logout.js +19 -0
  35. package/dist/tools/logout.js.map +1 -0
  36. package/dist/tools/remove-skill.d.ts +3 -0
  37. package/dist/tools/remove-skill.d.ts.map +1 -0
  38. package/dist/tools/remove-skill.js +110 -0
  39. package/dist/tools/remove-skill.js.map +1 -0
  40. package/dist/tools/scan-skill.d.ts.map +1 -1
  41. package/dist/tools/scan-skill.js +41 -18
  42. package/dist/tools/scan-skill.js.map +1 -1
  43. package/dist/tools/skill-permissions.d.ts +3 -0
  44. package/dist/tools/skill-permissions.d.ts.map +1 -0
  45. package/dist/tools/skill-permissions.js +311 -0
  46. package/dist/tools/skill-permissions.js.map +1 -0
  47. package/dist/tools/unlink-skill.d.ts +3 -0
  48. package/dist/tools/unlink-skill.d.ts.map +1 -0
  49. package/dist/tools/unlink-skill.js +72 -0
  50. package/dist/tools/unlink-skill.js.map +1 -0
  51. package/dist/tools/update-skill.d.ts +3 -0
  52. package/dist/tools/update-skill.d.ts.map +1 -0
  53. package/dist/tools/update-skill.js +317 -0
  54. package/dist/tools/update-skill.js.map +1 -0
  55. package/dist/tools/verify-skills.d.ts +3 -0
  56. package/dist/tools/verify-skills.d.ts.map +1 -0
  57. package/dist/tools/verify-skills.js +121 -0
  58. package/dist/tools/verify-skills.js.map +1 -0
  59. package/dist/tools/whoami.d.ts +3 -0
  60. package/dist/tools/whoami.d.ts.map +1 -0
  61. package/dist/tools/whoami.js +29 -0
  62. package/dist/tools/whoami.js.map +1 -0
  63. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unlink-skill.js","sourceRoot":"","sources":["../../src/tools/unlink-skill.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerUpdateSkillTool(server: McpServer): void;
3
+ //# sourceMappingURL=update-skill.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-skill.d.ts","sourceRoot":"","sources":["../../src/tools/update-skill.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA0BzE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA6U/D"}
@@ -0,0 +1,317 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { resolve } from '@tank/shared';
4
+ import { z } from 'zod';
5
+ import { TankApiClient } from '../lib/api-client.js';
6
+ const SCOPED_NAME_PATTERN = /^@[a-z0-9-]+\/[a-z0-9][a-z0-9-]*$/;
7
+ function parseLockKey(key) {
8
+ const lastAt = key.lastIndexOf('@');
9
+ if (lastAt <= 0)
10
+ return null;
11
+ return { name: key.slice(0, lastAt), version: key.slice(lastAt + 1) };
12
+ }
13
+ export function registerUpdateSkillTool(server) {
14
+ server.tool('update-skill', 'Update an installed skill to the latest compatible version within its declared semver range.', {
15
+ name: z.string().describe('Skill name in @org/name format'),
16
+ directory: z.string().optional().describe('Project directory (defaults to current working directory)'),
17
+ }, async ({ name, directory }) => {
18
+ if (!SCOPED_NAME_PATTERN.test(name)) {
19
+ return {
20
+ content: [{
21
+ type: 'text',
22
+ text: `Validation error: Skill name "${name}" must use the @org/name format (e.g. @acme/my-skill).`,
23
+ }],
24
+ isError: true,
25
+ };
26
+ }
27
+ const dir = directory ? path.resolve(directory) : process.cwd();
28
+ const skillsJsonPath = path.join(dir, 'skills.json');
29
+ if (!fs.existsSync(skillsJsonPath)) {
30
+ return {
31
+ content: [{
32
+ type: 'text',
33
+ text: `No skills.json found in ${dir}. Run the "init-skill" tool first.`,
34
+ }],
35
+ isError: true,
36
+ };
37
+ }
38
+ let skillsJson;
39
+ try {
40
+ const raw = fs.readFileSync(skillsJsonPath, 'utf-8');
41
+ skillsJson = JSON.parse(raw);
42
+ }
43
+ catch {
44
+ return {
45
+ content: [{
46
+ type: 'text',
47
+ text: 'Failed to read or parse skills.json.',
48
+ }],
49
+ isError: true,
50
+ };
51
+ }
52
+ const skills = (skillsJson.skills ?? {});
53
+ const versionRange = skills[name];
54
+ if (!versionRange) {
55
+ return {
56
+ content: [{
57
+ type: 'text',
58
+ text: `Skill "${name}" is not installed (not found in skills.json). Install it first with the install-skill tool.`,
59
+ }],
60
+ isError: true,
61
+ };
62
+ }
63
+ const lockPath = path.join(dir, 'skills.lock');
64
+ let currentVersion = null;
65
+ if (fs.existsSync(lockPath)) {
66
+ try {
67
+ const raw = fs.readFileSync(lockPath, 'utf-8');
68
+ const lock = JSON.parse(raw);
69
+ for (const key of Object.keys(lock.skills)) {
70
+ const parsed = parseLockKey(key);
71
+ if (!parsed)
72
+ continue;
73
+ if (parsed.name === name) {
74
+ currentVersion = parsed.version;
75
+ break;
76
+ }
77
+ }
78
+ }
79
+ catch {
80
+ // Lockfile unreadable — treat as no current version
81
+ }
82
+ }
83
+ if (!currentVersion) {
84
+ return {
85
+ content: [{
86
+ type: 'text',
87
+ text: `Skill "${name}" is not installed (not found in skills.lock). Install it first with the install-skill tool.`,
88
+ }],
89
+ isError: true,
90
+ };
91
+ }
92
+ const client = new TankApiClient();
93
+ if (!client.isAuthenticated) {
94
+ return {
95
+ content: [{
96
+ type: 'text',
97
+ text: 'Authentication required. Please run the "login" tool first to authenticate with Tank.',
98
+ }],
99
+ isError: true,
100
+ };
101
+ }
102
+ // Fetch available versions from registry
103
+ const encodedName = encodeURIComponent(name);
104
+ const versionsResult = await client.fetch(`/api/v1/skills/${encodedName}/versions`);
105
+ if (!versionsResult.ok) {
106
+ if (versionsResult.status === 0) {
107
+ return {
108
+ content: [{
109
+ type: 'text',
110
+ text: `Unable to connect to the Tank registry. Check your network connection and try again.`,
111
+ }],
112
+ isError: true,
113
+ };
114
+ }
115
+ if (versionsResult.status === 404) {
116
+ return {
117
+ content: [{
118
+ type: 'text',
119
+ text: `Skill "${name}" not found in the registry.`,
120
+ }],
121
+ isError: true,
122
+ };
123
+ }
124
+ return {
125
+ content: [{
126
+ type: 'text',
127
+ text: `Failed to fetch versions for ${name}: ${versionsResult.error}`,
128
+ }],
129
+ isError: true,
130
+ };
131
+ }
132
+ const availableVersions = versionsResult.data.versions.map((v) => v.version);
133
+ // 6. Resolve best version within declared range
134
+ const resolved = resolve(versionRange, availableVersions);
135
+ if (!resolved) {
136
+ return {
137
+ content: [{
138
+ type: 'text',
139
+ text: `No version of ${name} satisfies range "${versionRange}". Available: ${availableVersions.join(', ')}`,
140
+ }],
141
+ isError: true,
142
+ };
143
+ }
144
+ // 7. Check for newer major versions outside range
145
+ const allMajors = availableVersions
146
+ .map((v) => {
147
+ const major = v.split('.')[0];
148
+ return { version: v, major: parseInt(major, 10) };
149
+ })
150
+ .filter((v) => !isNaN(v.major));
151
+ const currentMajor = parseInt(currentVersion.split('.')[0], 10);
152
+ const newerMajors = allMajors
153
+ .filter((v) => v.major > currentMajor)
154
+ .map((v) => v.version);
155
+ const highestOutOfRange = newerMajors.length > 0
156
+ ? newerMajors.sort((a, b) => {
157
+ const [aMaj, aMin, aPat] = a.split('.').map(Number);
158
+ const [bMaj, bMin, bPat] = b.split('.').map(Number);
159
+ return bMaj - aMaj || bMin - aMin || bPat - aPat;
160
+ })[0]
161
+ : null;
162
+ // 8. If resolved === current, already at latest
163
+ if (resolved === currentVersion) {
164
+ const lines = [`Already at latest compatible version: ${name}@${resolved}`];
165
+ if (highestOutOfRange) {
166
+ lines.push(`\nNote: Version ${highestOutOfRange} is available but outside the declared range "${versionRange}". Update skills.json to use it.`);
167
+ }
168
+ return {
169
+ content: [{
170
+ type: 'text',
171
+ text: lines.join(''),
172
+ }],
173
+ };
174
+ }
175
+ // 9. Fetch the resolved version details for download
176
+ const versionResult = await client.fetch(`/api/v1/skills/${encodedName}/${resolved}`);
177
+ if (!versionResult.ok) {
178
+ return {
179
+ content: [{
180
+ type: 'text',
181
+ text: `Failed to fetch version details for ${name}@${resolved}: ${versionResult.error}`,
182
+ }],
183
+ isError: true,
184
+ };
185
+ }
186
+ const versionData = versionResult.data;
187
+ // 10. Download tarball
188
+ let tarballBuffer;
189
+ try {
190
+ const tarballRes = await fetch(versionData.downloadUrl, {
191
+ headers: client.token ? { Authorization: `Bearer ${client.token}` } : {},
192
+ });
193
+ if (!tarballRes.ok) {
194
+ return {
195
+ content: [{
196
+ type: 'text',
197
+ text: `Failed to download tarball for ${name}@${resolved}: ${tarballRes.statusText}`,
198
+ }],
199
+ isError: true,
200
+ };
201
+ }
202
+ tarballBuffer = await tarballRes.arrayBuffer();
203
+ }
204
+ catch (err) {
205
+ return {
206
+ content: [{
207
+ type: 'text',
208
+ text: `Network error downloading ${name}@${resolved}: ${err instanceof Error ? err.message : String(err)}`,
209
+ }],
210
+ isError: true,
211
+ };
212
+ }
213
+ // 11. Verify SHA-512
214
+ const { createHash } = await import('node:crypto');
215
+ const hash = createHash('sha512').update(Buffer.from(tarballBuffer)).digest('base64');
216
+ const computedIntegrity = `sha512-${hash}`;
217
+ if (computedIntegrity !== versionData.integrity) {
218
+ return {
219
+ content: [{
220
+ type: 'text',
221
+ text: `Integrity check failed for ${name}@${resolved}. The tarball has been tampered with or is corrupted.\nExpected: ${versionData.integrity}\nGot: ${computedIntegrity}`,
222
+ }],
223
+ isError: true,
224
+ };
225
+ }
226
+ // 12. Extract tarball to skill directory
227
+ const { execSync } = await import('node:child_process');
228
+ const skillDir = getSkillDir(dir, name);
229
+ // Remove old version files if they exist
230
+ if (fs.existsSync(skillDir)) {
231
+ fs.rmSync(skillDir, { recursive: true, force: true });
232
+ }
233
+ fs.mkdirSync(skillDir, { recursive: true });
234
+ const tarballPath = path.join(skillDir, '__temp_tarball.tgz');
235
+ fs.writeFileSync(tarballPath, Buffer.from(tarballBuffer));
236
+ try {
237
+ execSync(`tar xzf "${tarballPath}" -C "${skillDir}" --strip-components=1`, {
238
+ stdio: 'pipe',
239
+ });
240
+ }
241
+ catch (err) {
242
+ return {
243
+ content: [{
244
+ type: 'text',
245
+ text: `Failed to extract tarball for ${name}@${resolved}: ${err instanceof Error ? err.message : String(err)}`,
246
+ }],
247
+ isError: true,
248
+ };
249
+ }
250
+ finally {
251
+ // Clean up temp tarball
252
+ try {
253
+ fs.unlinkSync(tarballPath);
254
+ }
255
+ catch { /* ignore */ }
256
+ }
257
+ // 13. Update lockfile
258
+ let lock;
259
+ if (fs.existsSync(lockPath)) {
260
+ try {
261
+ const raw = fs.readFileSync(lockPath, 'utf-8');
262
+ lock = JSON.parse(raw);
263
+ }
264
+ catch {
265
+ lock = { lockfileVersion: 1, skills: {} };
266
+ }
267
+ }
268
+ else {
269
+ lock = { lockfileVersion: 1, skills: {} };
270
+ }
271
+ // Remove old lock entry for this skill
272
+ for (const key of Object.keys(lock.skills)) {
273
+ const parsed = parseLockKey(key);
274
+ if (parsed && parsed.name === name) {
275
+ delete lock.skills[key];
276
+ }
277
+ }
278
+ // Add new lock entry
279
+ const newLockKey = `${name}@${resolved}`;
280
+ lock.skills[newLockKey] = {
281
+ resolved: versionData.downloadUrl,
282
+ integrity: versionData.integrity,
283
+ permissions: versionData.permissions,
284
+ audit_score: versionData.auditScore,
285
+ };
286
+ // Sort keys for deterministic output
287
+ const sortedSkills = {};
288
+ for (const key of Object.keys(lock.skills).sort()) {
289
+ sortedSkills[key] = lock.skills[key];
290
+ }
291
+ lock.skills = sortedSkills;
292
+ fs.writeFileSync(lockPath, JSON.stringify(lock, null, 2) + '\n');
293
+ // 14. Build response
294
+ const lines = [
295
+ `Updated ${name} from ${currentVersion} to ${resolved}.`,
296
+ `Integrity verified (SHA-512).`,
297
+ `Lockfile updated.`,
298
+ ];
299
+ if (highestOutOfRange) {
300
+ lines.push(`\nNote: Version ${highestOutOfRange} is available but outside the declared range "${versionRange}". Update skills.json to use it.`);
301
+ }
302
+ return {
303
+ content: [{
304
+ type: 'text',
305
+ text: lines.join('\n'),
306
+ }],
307
+ };
308
+ });
309
+ }
310
+ function getSkillDir(projectDir, skillName) {
311
+ if (skillName.startsWith('@')) {
312
+ const [scope, name] = skillName.split('/');
313
+ return path.join(projectDir, '.tank', 'skills', scope, name);
314
+ }
315
+ return path.join(projectDir, '.tank', 'skills', skillName);
316
+ }
317
+ //# sourceMappingURL=update-skill.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-skill.js","sourceRoot":"","sources":["../../src/tools/update-skill.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerVerifySkillsTool(server: McpServer): void;
3
+ //# sourceMappingURL=verify-skills.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify-skills.d.ts","sourceRoot":"","sources":["../../src/tools/verify-skills.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIzE,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAyHhE"}
@@ -0,0 +1,121 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { z } from 'zod';
4
+ export function registerVerifySkillsTool(server) {
5
+ server.tool('verify-skills', 'Verify that installed skills match their lockfile entries. Checks that skill directories exist and are not empty.', {
6
+ name: z.string().optional().describe('Specific skill name to verify (verifies all if omitted)'),
7
+ directory: z.string().optional().describe('Project directory (defaults to current working directory)'),
8
+ }, async ({ name, directory }) => {
9
+ const dir = directory ? path.resolve(directory) : process.cwd();
10
+ const lockPath = path.join(dir, 'skills.lock');
11
+ if (!fs.existsSync(lockPath)) {
12
+ return {
13
+ content: [{
14
+ type: 'text',
15
+ text: 'No skills.lock found. Run "install-skill" to install skills and generate a lockfile.',
16
+ }],
17
+ isError: true,
18
+ };
19
+ }
20
+ let lock;
21
+ try {
22
+ const raw = fs.readFileSync(lockPath, 'utf-8');
23
+ lock = JSON.parse(raw);
24
+ }
25
+ catch {
26
+ return {
27
+ content: [{
28
+ type: 'text',
29
+ text: 'Failed to parse skills.lock. The file may be corrupted.',
30
+ }],
31
+ isError: true,
32
+ };
33
+ }
34
+ let entries = Object.entries(lock.skills);
35
+ if (entries.length === 0) {
36
+ return {
37
+ content: [{
38
+ type: 'text',
39
+ text: 'No skills to verify. The lockfile is empty.',
40
+ }],
41
+ };
42
+ }
43
+ if (name) {
44
+ entries = entries.filter(([key]) => {
45
+ const lastAt = key.lastIndexOf('@');
46
+ if (lastAt <= 0)
47
+ return false;
48
+ return key.slice(0, lastAt) === name;
49
+ });
50
+ if (entries.length === 0) {
51
+ return {
52
+ content: [{
53
+ type: 'text',
54
+ text: `Skill "${name}" not found in lockfile.`,
55
+ }],
56
+ isError: true,
57
+ };
58
+ }
59
+ }
60
+ const results = [];
61
+ for (const [key, entry] of entries) {
62
+ const skillName = parseLockKey(key);
63
+ const skillDir = getExtractDir(dir, skillName);
64
+ if (!fs.existsSync(skillDir)) {
65
+ results.push({
66
+ key,
67
+ status: 'MISSING',
68
+ detail: `Directory missing at ${skillDir}. Reinstall with "install-skill".`,
69
+ });
70
+ continue;
71
+ }
72
+ const contents = fs.readdirSync(skillDir);
73
+ if (contents.length === 0) {
74
+ results.push({
75
+ key,
76
+ status: 'FAIL',
77
+ detail: `Directory exists but is empty. Expected integrity: ${entry.integrity}. SHA-512 mismatch detected.`,
78
+ });
79
+ continue;
80
+ }
81
+ results.push({
82
+ key,
83
+ status: 'PASS',
84
+ detail: `Verified (integrity: ${entry.integrity})`,
85
+ });
86
+ }
87
+ const passing = results.filter((r) => r.status === 'PASS');
88
+ const failing = results.filter((r) => r.status !== 'PASS');
89
+ const lines = [];
90
+ for (const r of results) {
91
+ lines.push(`${r.status} ${r.key}: ${r.detail}`);
92
+ }
93
+ if (failing.length > 0) {
94
+ lines.push('');
95
+ lines.push(`Verification failed: ${failing.length} issue(s) found, ${passing.length} passed.`);
96
+ return {
97
+ content: [{ type: 'text', text: lines.join('\n') }],
98
+ isError: true,
99
+ };
100
+ }
101
+ lines.push('');
102
+ lines.push(`All ${passing.length} skill(s) passed verification.`);
103
+ return {
104
+ content: [{ type: 'text', text: lines.join('\n') }],
105
+ };
106
+ });
107
+ }
108
+ function parseLockKey(key) {
109
+ const lastAt = key.lastIndexOf('@');
110
+ if (lastAt <= 0)
111
+ return key;
112
+ return key.slice(0, lastAt);
113
+ }
114
+ function getExtractDir(projectDir, skillName) {
115
+ if (skillName.startsWith('@')) {
116
+ const [scope, name] = skillName.split('/');
117
+ return path.join(projectDir, '.tank', 'skills', scope, name);
118
+ }
119
+ return path.join(projectDir, '.tank', 'skills', skillName);
120
+ }
121
+ //# sourceMappingURL=verify-skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify-skills.js","sourceRoot":"","sources":["../../src/tools/verify-skills.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerWhoamiTool(server: McpServer): void;
3
+ //# sourceMappingURL=whoami.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoami.d.ts","sourceRoot":"","sources":["../../src/tools/whoami.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGzE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAoC1D"}
@@ -0,0 +1,29 @@
1
+ import { TankApiClient } from '../lib/api-client.js';
2
+ export function registerWhoamiTool(server) {
3
+ server.tool('whoami', 'Show the authenticated Tank user for the current local session.', {}, async () => {
4
+ const client = new TankApiClient();
5
+ if (!client.isAuthenticated) {
6
+ return {
7
+ content: [{ type: 'text', text: 'Not logged in. Use the login tool to authenticate.' }],
8
+ };
9
+ }
10
+ const authCheck = await client.verifyAuth();
11
+ if (authCheck.valid) {
12
+ const name = authCheck.user.name ?? 'unknown';
13
+ const email = authCheck.user.email ?? 'unknown';
14
+ return {
15
+ content: [{ type: 'text', text: `Logged in as ${name}\nEmail: ${email}` }],
16
+ };
17
+ }
18
+ if (authCheck.reason === 'network-error') {
19
+ return {
20
+ content: [{ type: 'text', text: `Failed to connect to the registry. Check your network connection.\nError: ${authCheck.error ?? 'unknown'}` }],
21
+ isError: true,
22
+ };
23
+ }
24
+ return {
25
+ content: [{ type: 'text', text: 'Session expired or invalid. Use the login tool to re-authenticate.' }],
26
+ };
27
+ });
28
+ }
29
+ //# sourceMappingURL=whoami.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../src/tools/whoami.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,UAAU,kBAAkB,CAAC,MAAiB;IAClD,MAAM,CAAC,IAAI,CACT,QAAQ,EACR,iEAAiE,EACjE,EAAE,EACF,KAAK,IAAI,EAAE;QACT,MAAM,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;QAEnC,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC;YAC5B,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,oDAAoD,EAAE,CAAC;aACjG,CAAC;QACJ,CAAC;QAED,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC;QAE5C,IAAI,SAAS,CAAC,KAAK,EAAE,CAAC;YACpB,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,SAAS,CAAC;YAC9C,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,SAAS,CAAC;YAChD,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,gBAAgB,IAAI,YAAY,KAAK,EAAE,EAAE,CAAC;aACpF,CAAC;QACJ,CAAC;QAED,IAAI,SAAS,CAAC,MAAM,KAAK,eAAe,EAAE,CAAC;YACzC,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,6EAA6E,SAAS,CAAC,KAAK,IAAI,SAAS,EAAE,EAAE,CAAC;gBACvJ,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAED,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,oEAAoE,EAAE,CAAC;SACjH,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tankpkg/mcp-server",
3
- "version": "0.4.2",
3
+ "version": "0.5.0",
4
4
  "description": "MCP server for Tank - scan and publish AI agent skills from your editor",
5
5
  "type": "module",
6
6
  "bin": {