tokrepo-mcp-server 2.1.0 → 2.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.
Files changed (3) hide show
  1. package/README.md +5 -0
  2. package/bin/server.js +198 -4
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -40,6 +40,7 @@ Once connected, your AI assistant can:
40
40
  - **Get details** — full documentation, install instructions, and metadata
41
41
  - **Plan before install** — get install plan v2 with policy decisions, rollback, and verification
42
42
  - **Safe Codex install** — dry-run by default; risky assets must be staged or explicitly approved
43
+ - **Lifecycle control** — list installed assets, uninstall managed files, and roll back install sessions
43
44
 
44
45
  ## Available Tools
45
46
 
@@ -50,6 +51,9 @@ Once connected, your AI assistant can:
50
51
  | `tokrepo_install_plan` | Get agent-native install plan v2 |
51
52
  | `tokrepo_codex_install` | Dry-run, stage, or install a Codex skill safely |
52
53
  | `tokrepo_clone_plan` | Bulk profile clone dry-run plan |
54
+ | `tokrepo_installed` | List TokRepo-managed Codex installs |
55
+ | `tokrepo_uninstall` | Dry-run or remove a managed Codex install |
56
+ | `tokrepo_rollback` | Dry-run or roll back a prior Codex install session |
53
57
  | `tokrepo_install` | Get raw installable content |
54
58
  | `tokrepo_trending` | Browse popular/latest assets |
55
59
 
@@ -65,6 +69,7 @@ AI: [calls tokrepo_trending] → Shows top assets by popularity
65
69
  You: "Install that cursor rules asset"
66
70
  AI: [calls tokrepo_install_plan] → Reviews policy and actions
67
71
  AI: [calls tokrepo_codex_install with dry_run=false, confirm=true] → Writes only after explicit confirmation
72
+ AI: [calls tokrepo_rollback with dry_run=true] → Shows exactly what would be removed before rollback
68
73
  ```
69
74
 
70
75
  ## Why TokRepo?
package/bin/server.js CHANGED
@@ -19,7 +19,7 @@ const API_BASE = process.env.TOKREPO_API || 'https://api.tokrepo.com';
19
19
  const TOKREPO_URL = 'https://tokrepo.com';
20
20
  const TOKREPO_TOKEN = process.env.TOKREPO_TOKEN || '';
21
21
  const TOKREPO_CLI = process.env.TOKREPO_CLI || '';
22
- const SERVER_VERSION = '2.1.0';
22
+ const SERVER_VERSION = '2.2.0';
23
23
 
24
24
  // ─── MCP Protocol (JSON-RPC over stdio) ───
25
25
 
@@ -53,6 +53,20 @@ const TOOLS = [
53
53
  description: 'Max results (default 10, max 20)',
54
54
  default: 10,
55
55
  },
56
+ target: {
57
+ type: 'string',
58
+ description: 'Optional agent target filter. Use codex for Codex-compatible assets.',
59
+ enum: ['codex'],
60
+ },
61
+ kind: {
62
+ type: 'string',
63
+ description: 'Optional asset kind filter, e.g. skill, prompt, knowledge, mcp_config, script',
64
+ },
65
+ policy: {
66
+ type: 'string',
67
+ description: 'Optional Codex install policy filter.',
68
+ enum: ['allow', 'confirm', 'stage_only', 'deny'],
69
+ },
56
70
  },
57
71
  required: ['query'],
58
72
  },
@@ -161,6 +175,76 @@ const TOOLS = [
161
175
  required: ['user'],
162
176
  },
163
177
  },
178
+ {
179
+ name: 'tokrepo_installed',
180
+ description: 'List Codex assets installed by TokRepo from the local install manifest, including file status and session ids.',
181
+ inputSchema: {
182
+ type: 'object',
183
+ properties: {},
184
+ },
185
+ },
186
+ {
187
+ name: 'tokrepo_uninstall',
188
+ description: 'Safely uninstall a TokRepo-managed Codex asset. Defaults to dry_run=true. To remove files, set dry_run=false and confirm=true. Local changes are blocked unless force=true.',
189
+ inputSchema: {
190
+ type: 'object',
191
+ properties: {
192
+ uuid: {
193
+ type: 'string',
194
+ description: 'Installed asset UUID, UUID prefix, or title.',
195
+ },
196
+ dry_run: {
197
+ type: 'boolean',
198
+ description: 'When true, return the removal plan without deleting files. Default true.',
199
+ default: true,
200
+ },
201
+ confirm: {
202
+ type: 'boolean',
203
+ description: 'Required when dry_run=false to prevent accidental deletes.',
204
+ default: false,
205
+ },
206
+ force: {
207
+ type: 'boolean',
208
+ description: 'Allow removal when local files changed since installation.',
209
+ default: false,
210
+ },
211
+ },
212
+ required: ['uuid'],
213
+ },
214
+ },
215
+ {
216
+ name: 'tokrepo_rollback',
217
+ description: 'Roll back a previous TokRepo Codex install session. Defaults to dry_run=true and last=true.',
218
+ inputSchema: {
219
+ type: 'object',
220
+ properties: {
221
+ session_id: {
222
+ type: 'string',
223
+ description: 'Session id to roll back. Omit when last=true.',
224
+ },
225
+ last: {
226
+ type: 'boolean',
227
+ description: 'Use the latest install/stage session. Default true.',
228
+ default: true,
229
+ },
230
+ dry_run: {
231
+ type: 'boolean',
232
+ description: 'When true, return the rollback plan without deleting files. Default true.',
233
+ default: true,
234
+ },
235
+ confirm: {
236
+ type: 'boolean',
237
+ description: 'Required when dry_run=false to prevent accidental deletes.',
238
+ default: false,
239
+ },
240
+ force: {
241
+ type: 'boolean',
242
+ description: 'Allow rollback when local files changed since installation.',
243
+ default: false,
244
+ },
245
+ },
246
+ },
247
+ },
164
248
  {
165
249
  name: 'tokrepo_trending',
166
250
  description: 'Get trending/popular AI assets on TokRepo. Use when user asks for recommended or popular AI tools.',
@@ -435,7 +519,22 @@ function jsonText(title, data) {
435
519
  // ─── Tool Handlers ───
436
520
 
437
521
  async function handleSearch(args) {
438
- const { query, tag, limit = 10 } = args;
522
+ const { query, tag, limit = 10, target = '', kind = '', policy = '' } = args;
523
+ if (target || kind || policy) {
524
+ const cliArgs = ['search', query, '--json', '--page-size', String(Math.min(limit, 20))];
525
+ if (target) cliArgs.push('--target', target);
526
+ if (kind) cliArgs.push('--kind', kind);
527
+ if (policy) cliArgs.push('--policy', policy);
528
+ const { stdout, stderr } = await runTokrepoCli(cliArgs);
529
+ let data;
530
+ try {
531
+ data = JSON.parse(stdout);
532
+ } catch {
533
+ data = { stdout, stderr };
534
+ }
535
+ return { content: [{ type: 'text', text: jsonText('Filtered TokRepo search results', data) }] };
536
+ }
537
+
439
538
  // Normalize: hyphens/underscores/dots → spaces for better matching
440
539
  const normalized = query.replace(/[-_.]/g, ' ').replace(/\s+/g, ' ').trim();
441
540
  const params = new URLSearchParams({
@@ -551,20 +650,37 @@ async function handleCodexInstall(args) {
551
650
  const plan = await fetchInstallPlan(uuid, 'codex');
552
651
  const decision = planPolicyDecision(plan);
553
652
  if (dry_run !== false) {
653
+ const cliArgs = ['install', plan.asset_uuid || uuid, '--target', 'codex', '--dry-run', '--json'];
654
+ if (stage) cliArgs.push('--stage');
655
+ const { stdout, stderr } = await runTokrepoCli(cliArgs);
656
+ let data;
657
+ try {
658
+ data = JSON.parse(stdout);
659
+ } catch {
660
+ data = { stdout, stderr };
661
+ }
554
662
  return {
555
663
  content: [{
556
664
  type: 'text',
557
- text: jsonText(`Dry run only. Policy: ${decision}. Set dry_run=false and confirm=true to write files.`, plan),
665
+ text: jsonText(`Dry run only. Policy: ${decision}. Set dry_run=false and confirm=true to write files.`, data),
558
666
  }],
559
667
  };
560
668
  }
561
669
 
562
670
  if (!confirm) {
671
+ const cliArgs = ['install', plan.asset_uuid || uuid, '--target', 'codex', '--dry-run', '--json'];
672
+ const { stdout, stderr } = await runTokrepoCli(cliArgs);
673
+ let data;
674
+ try {
675
+ data = JSON.parse(stdout);
676
+ } catch {
677
+ data = { stdout, stderr };
678
+ }
563
679
  return {
564
680
  isError: true,
565
681
  content: [{
566
682
  type: 'text',
567
- text: jsonText('Refused to write files because confirm=true was not provided.', plan),
683
+ text: jsonText('Refused to write files because confirm=true was not provided. Dry-run plan follows.', data),
568
684
  }],
569
685
  };
570
686
  }
@@ -612,6 +728,81 @@ async function handleClonePlan(args) {
612
728
  return { content: [{ type: 'text', text: jsonText('Bulk Codex clone dry-run plan', data) }] };
613
729
  }
614
730
 
731
+ async function handleInstalled() {
732
+ const { stdout, stderr } = await runTokrepoCli(['installed', '--target', 'codex', '--json']);
733
+ let data;
734
+ try {
735
+ data = JSON.parse(stdout);
736
+ } catch {
737
+ data = { stdout, stderr };
738
+ }
739
+ return { content: [{ type: 'text', text: jsonText('TokRepo Codex installed assets', data) }] };
740
+ }
741
+
742
+ async function handleUninstall(args) {
743
+ const { uuid, dry_run = true, confirm = false, force = false } = args;
744
+ const cliArgs = ['uninstall', uuid, '--target', 'codex', '--json'];
745
+ if (dry_run !== false) cliArgs.push('--dry-run');
746
+ if (force) cliArgs.push('--force');
747
+
748
+ if (dry_run === false && !confirm) {
749
+ cliArgs.push('--dry-run');
750
+ const { stdout, stderr } = await runTokrepoCli(cliArgs);
751
+ let data;
752
+ try {
753
+ data = JSON.parse(stdout);
754
+ } catch {
755
+ data = { stdout, stderr };
756
+ }
757
+ return {
758
+ isError: true,
759
+ content: [{ type: 'text', text: jsonText('Refused to uninstall because confirm=true was not provided. Dry-run plan follows.', data) }],
760
+ };
761
+ }
762
+
763
+ const { stdout, stderr } = await runTokrepoCli(cliArgs);
764
+ let data;
765
+ try {
766
+ data = JSON.parse(stdout);
767
+ } catch {
768
+ data = { stdout, stderr };
769
+ }
770
+ return { content: [{ type: 'text', text: jsonText(dry_run === false ? 'TokRepo Codex uninstall result' : 'TokRepo Codex uninstall dry-run', data) }] };
771
+ }
772
+
773
+ async function handleRollback(args) {
774
+ const { session_id = '', last = true, dry_run = true, confirm = false, force = false } = args;
775
+ const cliArgs = ['rollback', '--target', 'codex', '--json'];
776
+ if (session_id) cliArgs.push(session_id);
777
+ else if (last !== false) cliArgs.push('--last');
778
+ if (dry_run !== false) cliArgs.push('--dry-run');
779
+ if (force) cliArgs.push('--force');
780
+
781
+ if (dry_run === false && !confirm) {
782
+ cliArgs.push('--dry-run');
783
+ const { stdout, stderr } = await runTokrepoCli(cliArgs);
784
+ let data;
785
+ try {
786
+ data = JSON.parse(stdout);
787
+ } catch {
788
+ data = { stdout, stderr };
789
+ }
790
+ return {
791
+ isError: true,
792
+ content: [{ type: 'text', text: jsonText('Refused to roll back because confirm=true was not provided. Dry-run plan follows.', data) }],
793
+ };
794
+ }
795
+
796
+ const { stdout, stderr } = await runTokrepoCli(cliArgs);
797
+ let data;
798
+ try {
799
+ data = JSON.parse(stdout);
800
+ } catch {
801
+ data = { stdout, stderr };
802
+ }
803
+ return { content: [{ type: 'text', text: jsonText(dry_run === false ? 'TokRepo Codex rollback result' : 'TokRepo Codex rollback dry-run', data) }] };
804
+ }
805
+
615
806
  async function handleTrending(args) {
616
807
  const { sort = 'popular', limit = 10 } = args;
617
808
  const params = new URLSearchParams({
@@ -763,6 +954,9 @@ async function handleRequest(msg) {
763
954
  case 'tokrepo_install_plan': result = await handleInstallPlan(args || {}); break;
764
955
  case 'tokrepo_codex_install': result = await handleCodexInstall(args || {}); break;
765
956
  case 'tokrepo_clone_plan': result = await handleClonePlan(args || {}); break;
957
+ case 'tokrepo_installed': result = await handleInstalled(args || {}); break;
958
+ case 'tokrepo_uninstall': result = await handleUninstall(args || {}); break;
959
+ case 'tokrepo_rollback': result = await handleRollback(args || {}); break;
766
960
  case 'tokrepo_trending': result = await handleTrending(args || {}); break;
767
961
  case 'tokrepo_push': result = await handlePush(args || {}); break;
768
962
  case 'tokrepo_status': result = await handleStatus(args || {}); break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tokrepo-mcp-server",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "Agent-native MCP server for TokRepo — search, plan, safely install, and push AI assets from MCP clients.",
5
5
  "mcpName": "io.github.tokrepo/mcp-server",
6
6
  "bin": {