@thantos66/claude-context-mcp 0.1.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 (60) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +171 -0
  3. package/dist/constants.d.ts +33 -0
  4. package/dist/constants.js +59 -0
  5. package/dist/constants.js.map +1 -0
  6. package/dist/index.d.ts +2 -0
  7. package/dist/index.js +44 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/schemas/agent-frontmatter.d.ts +55 -0
  10. package/dist/schemas/agent-frontmatter.js +43 -0
  11. package/dist/schemas/agent-frontmatter.js.map +1 -0
  12. package/dist/schemas/mcp-config.d.ts +177 -0
  13. package/dist/schemas/mcp-config.js +38 -0
  14. package/dist/schemas/mcp-config.js.map +1 -0
  15. package/dist/schemas/settings.d.ts +70 -0
  16. package/dist/schemas/settings.js +28 -0
  17. package/dist/schemas/settings.js.map +1 -0
  18. package/dist/schemas/skill-frontmatter.d.ts +42 -0
  19. package/dist/schemas/skill-frontmatter.js +27 -0
  20. package/dist/schemas/skill-frontmatter.js.map +1 -0
  21. package/dist/services/agents.d.ts +56 -0
  22. package/dist/services/agents.js +155 -0
  23. package/dist/services/agents.js.map +1 -0
  24. package/dist/services/atomic-write.d.ts +10 -0
  25. package/dist/services/atomic-write.js +46 -0
  26. package/dist/services/atomic-write.js.map +1 -0
  27. package/dist/services/backup.d.ts +13 -0
  28. package/dist/services/backup.js +52 -0
  29. package/dist/services/backup.js.map +1 -0
  30. package/dist/services/mcp-config.d.ts +72 -0
  31. package/dist/services/mcp-config.js +163 -0
  32. package/dist/services/mcp-config.js.map +1 -0
  33. package/dist/services/paths.d.ts +42 -0
  34. package/dist/services/paths.js +91 -0
  35. package/dist/services/paths.js.map +1 -0
  36. package/dist/services/permissions.d.ts +38 -0
  37. package/dist/services/permissions.js +104 -0
  38. package/dist/services/permissions.js.map +1 -0
  39. package/dist/services/skills.d.ts +62 -0
  40. package/dist/services/skills.js +181 -0
  41. package/dist/services/skills.js.map +1 -0
  42. package/dist/tools/agents.d.ts +2 -0
  43. package/dist/tools/agents.js +134 -0
  44. package/dist/tools/agents.js.map +1 -0
  45. package/dist/tools/helpers.d.ts +25 -0
  46. package/dist/tools/helpers.js +36 -0
  47. package/dist/tools/helpers.js.map +1 -0
  48. package/dist/tools/mcp.d.ts +2 -0
  49. package/dist/tools/mcp.js +257 -0
  50. package/dist/tools/mcp.js.map +1 -0
  51. package/dist/tools/meta.d.ts +2 -0
  52. package/dist/tools/meta.js +79 -0
  53. package/dist/tools/meta.js.map +1 -0
  54. package/dist/tools/permissions.d.ts +2 -0
  55. package/dist/tools/permissions.js +144 -0
  56. package/dist/tools/permissions.js.map +1 -0
  57. package/dist/tools/skills.d.ts +2 -0
  58. package/dist/tools/skills.js +160 -0
  59. package/dist/tools/skills.js.map +1 -0
  60. package/package.json +55 -0
@@ -0,0 +1,181 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import matter from "gray-matter";
4
+ import { SkillFrontmatterSchema, } from "../schemas/skill-frontmatter.js";
5
+ import { atomicWriteFile } from "./atomic-write.js";
6
+ import { backupFile, backupDir } from "./backup.js";
7
+ import { skillsDirFor } from "./paths.js";
8
+ /** List all skill folders under the scope's skills dir. */
9
+ export async function listSkills(scope, projectPath) {
10
+ const dir = skillsDirFor(scope, projectPath);
11
+ let names;
12
+ try {
13
+ names = await fs.readdir(dir);
14
+ }
15
+ catch (err) {
16
+ if (err.code === "ENOENT")
17
+ return [];
18
+ throw err;
19
+ }
20
+ const results = [];
21
+ for (const name of names) {
22
+ const skillDir = path.join(dir, name);
23
+ const stat = await fs.stat(skillDir).catch(() => null);
24
+ if (!stat?.isDirectory())
25
+ continue;
26
+ try {
27
+ const rec = await readSkillFolder(scope, skillDir);
28
+ results.push(rec);
29
+ }
30
+ catch {
31
+ continue; // skip malformed skills
32
+ }
33
+ }
34
+ return results;
35
+ }
36
+ async function readSkillFolder(scope, skillDir) {
37
+ const skillMdPath = path.join(skillDir, "SKILL.md");
38
+ const raw = await fs.readFile(skillMdPath, "utf8");
39
+ const parsed = matter(raw);
40
+ const frontmatter = SkillFrontmatterSchema.parse(parsed.data);
41
+ return {
42
+ scope,
43
+ name: frontmatter.name,
44
+ dir: skillDir,
45
+ skillMdPath,
46
+ frontmatter,
47
+ body: parsed.content.trimStart(),
48
+ };
49
+ }
50
+ export async function getSkill(params) {
51
+ const skillDir = path.join(skillsDirFor(params.scope, params.projectPath), params.name);
52
+ try {
53
+ return await readSkillFolder(params.scope, skillDir);
54
+ }
55
+ catch (err) {
56
+ if (err.code === "ENOENT")
57
+ return null;
58
+ throw err;
59
+ }
60
+ }
61
+ /** Serialize a skill record to SKILL.md contents. */
62
+ export function serializeSkill(frontmatter, body) {
63
+ const ordered = {
64
+ name: frontmatter.name,
65
+ description: frontmatter.description,
66
+ };
67
+ const knownOrder = [
68
+ "allowed-tools",
69
+ "disable-model-invocation",
70
+ "user-invocable",
71
+ "model",
72
+ "effort",
73
+ "context",
74
+ "paths",
75
+ ];
76
+ for (const k of knownOrder) {
77
+ const v = frontmatter[k];
78
+ if (v !== undefined)
79
+ ordered[k] = v;
80
+ }
81
+ for (const [k, v] of Object.entries(frontmatter)) {
82
+ if (v === undefined)
83
+ continue;
84
+ if (!(k in ordered))
85
+ ordered[k] = v;
86
+ }
87
+ const bodyText = body.endsWith("\n") ? body : body + "\n";
88
+ return matter.stringify(bodyText, ordered);
89
+ }
90
+ /** Scaffold a new skill folder with a SKILL.md. */
91
+ export async function createSkill(params) {
92
+ const frontmatter = SkillFrontmatterSchema.parse({
93
+ name: params.name,
94
+ description: params.description,
95
+ ...(params.allowedTools !== undefined && { "allowed-tools": params.allowedTools }),
96
+ ...(params.model !== undefined && { model: params.model }),
97
+ });
98
+ const body = params.body ?? `# ${frontmatter.name}\n\n${frontmatter.description}\n`;
99
+ const skillDir = path.join(skillsDirFor(params.scope, params.projectPath), frontmatter.name);
100
+ const skillMdPath = path.join(skillDir, "SKILL.md");
101
+ if (!params.overwrite) {
102
+ try {
103
+ await fs.access(skillMdPath);
104
+ throw new Error(`Skill "${frontmatter.name}" already exists at ${skillDir}. Pass overwrite: true to replace.`);
105
+ }
106
+ catch (err) {
107
+ if (err.code !== "ENOENT")
108
+ throw err;
109
+ }
110
+ }
111
+ const contents = serializeSkill(frontmatter, body);
112
+ if (params.dryRun) {
113
+ return { path: skillMdPath, backup: null, dryRun: true, preview: contents };
114
+ }
115
+ await fs.mkdir(skillDir, { recursive: true });
116
+ const backup = await backupFile(skillMdPath);
117
+ await atomicWriteFile(skillMdPath, contents);
118
+ return { path: skillMdPath, backup, dryRun: false };
119
+ }
120
+ /** Patch frontmatter fields or replace the SKILL.md body. */
121
+ export async function updateSkill(params) {
122
+ const current = await getSkill({
123
+ scope: params.scope,
124
+ name: params.name,
125
+ projectPath: params.projectPath,
126
+ });
127
+ if (!current)
128
+ throw new Error(`Skill "${params.name}" not found in scope ${params.scope}.`);
129
+ const merged = SkillFrontmatterSchema.parse({
130
+ ...current.frontmatter,
131
+ ...(params.description !== undefined && { description: params.description }),
132
+ ...(params.allowedTools !== undefined && { "allowed-tools": params.allowedTools }),
133
+ ...(params.model !== undefined && { model: params.model }),
134
+ });
135
+ const body = params.body ?? current.body;
136
+ const contents = serializeSkill(merged, body);
137
+ if (params.dryRun) {
138
+ return { path: current.skillMdPath, backup: null, dryRun: true, preview: contents };
139
+ }
140
+ const backup = await backupFile(current.skillMdPath);
141
+ await atomicWriteFile(current.skillMdPath, contents);
142
+ return { path: current.skillMdPath, backup, dryRun: false };
143
+ }
144
+ /** Toggle `disable-model-invocation` flag while preserving files. */
145
+ export async function setSkillEnabled(params) {
146
+ const current = await getSkill({
147
+ scope: params.scope,
148
+ name: params.name,
149
+ projectPath: params.projectPath,
150
+ });
151
+ if (!current)
152
+ throw new Error(`Skill "${params.name}" not found in scope ${params.scope}.`);
153
+ const merged = SkillFrontmatterSchema.parse({
154
+ ...current.frontmatter,
155
+ "disable-model-invocation": !params.enabled,
156
+ });
157
+ const contents = serializeSkill(merged, current.body);
158
+ if (params.dryRun) {
159
+ return { path: current.skillMdPath, backup: null, dryRun: true, preview: contents };
160
+ }
161
+ const backup = await backupFile(current.skillMdPath);
162
+ await atomicWriteFile(current.skillMdPath, contents);
163
+ return { path: current.skillMdPath, backup, dryRun: false };
164
+ }
165
+ /** Remove a skill folder entirely. Backs up the full directory first. */
166
+ export async function deleteSkill(params) {
167
+ const current = await getSkill({
168
+ scope: params.scope,
169
+ name: params.name,
170
+ projectPath: params.projectPath,
171
+ });
172
+ if (!current)
173
+ throw new Error(`Skill "${params.name}" not found in scope ${params.scope}.`);
174
+ if (params.dryRun) {
175
+ return { path: current.dir, backup: null, dryRun: true };
176
+ }
177
+ const backup = await backupDir(current.dir);
178
+ await fs.rm(current.dir, { recursive: true, force: true });
179
+ return { path: current.dir, backup, dryRun: false };
180
+ }
181
+ //# sourceMappingURL=skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/services/skills.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EACL,sBAAsB,GAEvB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAkB1C,2DAA2D;AAC3D,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,KAAyB,EACzB,WAAoB;IAEpB,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;IAC7C,IAAI,KAAe,CAAC;IACpB,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,EAAE,CAAC;QAChE,MAAM,GAAG,CAAC;IACZ,CAAC;IACD,MAAM,OAAO,GAAkB,EAAE,CAAC;IAClC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACtC,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QACvD,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE;YAAE,SAAS;QACnC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YACnD,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACpB,CAAC;QAAC,MAAM,CAAC;YACP,SAAS,CAAC,wBAAwB;QACpC,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,KAAK,UAAU,eAAe,CAC5B,KAAyB,EACzB,QAAgB;IAEhB,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IACpD,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IACnD,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC3B,MAAM,WAAW,GAAG,sBAAsB,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC9D,OAAO;QACL,KAAK;QACL,IAAI,EAAE,WAAW,CAAC,IAAI;QACtB,GAAG,EAAE,QAAQ;QACb,WAAW;QACX,WAAW;QACX,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE;KACjC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,MAI9B;IACC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CACxB,YAAY,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC,EAC9C,MAAM,CAAC,IAAI,CACZ,CAAC;IACF,IAAI,CAAC;QACH,OAAO,MAAM,eAAe,CAAC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IACvD,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QAClE,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,cAAc,CAC5B,WAA6B,EAC7B,IAAY;IAEZ,MAAM,OAAO,GAA4B;QACvC,IAAI,EAAE,WAAW,CAAC,IAAI;QACtB,WAAW,EAAE,WAAW,CAAC,WAAW;KACrC,CAAC;IACF,MAAM,UAAU,GAAG;QACjB,eAAe;QACf,0BAA0B;QAC1B,gBAAgB;QAChB,OAAO;QACP,QAAQ;QACR,SAAS;QACT,OAAO;KACR,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,MAAM,CAAC,GAAI,WAAuC,CAAC,CAAC,CAAC,CAAC;QACtD,IAAI,CAAC,KAAK,SAAS;YAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACtC,CAAC;IACD,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QACjD,IAAI,CAAC,KAAK,SAAS;YAAE,SAAS;QAC9B,IAAI,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC;YAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACtC,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC;IAC1D,OAAO,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AAC7C,CAAC;AAED,mDAAmD;AACnD,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAUjC;IACC,MAAM,WAAW,GAAG,sBAAsB,CAAC,KAAK,CAAC;QAC/C,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,GAAG,CAAC,MAAM,CAAC,YAAY,KAAK,SAAS,IAAI,EAAE,eAAe,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC;QAClF,GAAG,CAAC,MAAM,CAAC,KAAK,KAAK,SAAS,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;KAC3D,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,KAAK,WAAW,CAAC,IAAI,OAAO,WAAW,CAAC,WAAW,IAAI,CAAC;IACpF,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CACxB,YAAY,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC,EAC9C,WAAW,CAAC,IAAI,CACjB,CAAC;IACF,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAEpD,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACtB,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YAC7B,MAAM,IAAI,KAAK,CACb,UAAU,WAAW,CAAC,IAAI,uBAAuB,QAAQ,oCAAoC,CAC9F,CAAC;QACJ,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ;gBAAE,MAAM,GAAG,CAAC;QAClE,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,cAAc,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;IACnD,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;IAC9E,CAAC;IACD,MAAM,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,WAAW,CAAC,CAAC;IAC7C,MAAM,eAAe,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IAC7C,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AACtD,CAAC;AAED,6DAA6D;AAC7D,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MASjC;IACC,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC;QAC7B,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,WAAW,EAAE,MAAM,CAAC,WAAW;KAChC,CAAC,CAAC;IACH,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,UAAU,MAAM,CAAC,IAAI,wBAAwB,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC;IAC5F,MAAM,MAAM,GAAG,sBAAsB,CAAC,KAAK,CAAC;QAC1C,GAAG,OAAO,CAAC,WAAW;QACtB,GAAG,CAAC,MAAM,CAAC,WAAW,KAAK,SAAS,IAAI,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC;QAC5E,GAAG,CAAC,MAAM,CAAC,YAAY,KAAK,SAAS,IAAI,EAAE,eAAe,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC;QAClF,GAAG,CAAC,MAAM,CAAC,KAAK,KAAK,SAAS,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;KAC3D,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IACzC,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC9C,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;IACtF,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACrD,MAAM,eAAe,CAAC,OAAO,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IACrD,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAC9D,CAAC;AAED,qEAAqE;AACrE,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MAMrC;IACC,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC;QAC7B,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,WAAW,EAAE,MAAM,CAAC,WAAW;KAChC,CAAC,CAAC;IACH,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,UAAU,MAAM,CAAC,IAAI,wBAAwB,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC;IAC5F,MAAM,MAAM,GAAG,sBAAsB,CAAC,KAAK,CAAC;QAC1C,GAAG,OAAO,CAAC,WAAW;QACtB,0BAA0B,EAAE,CAAC,MAAM,CAAC,OAAO;KAC5C,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;IACtF,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACrD,MAAM,eAAe,CAAC,OAAO,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IACrD,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAC9D,CAAC;AAED,yEAAyE;AACzE,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAKjC;IACC,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC;QAC7B,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,WAAW,EAAE,MAAM,CAAC,WAAW;KAChC,CAAC,CAAC;IACH,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,UAAU,MAAM,CAAC,IAAI,wBAAwB,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC;IAC5F,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAC3D,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC5C,MAAM,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3D,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AACtD,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerAgentTools(server: McpServer): void;
@@ -0,0 +1,134 @@
1
+ import { z } from "zod";
2
+ import { listAgents, getAgent, createAgent, updateAgent, deleteAgent, } from "../services/agents.js";
3
+ import { handle, okResponse, formatWriteResult } from "./helpers.js";
4
+ const CodeScope = z.enum(["user", "project"]);
5
+ const ProjectPathField = {
6
+ projectPath: z
7
+ .string()
8
+ .optional()
9
+ .describe("Absolute path to the project. Required when scope=project."),
10
+ };
11
+ const DryRunField = {
12
+ dryRun: z.boolean().optional(),
13
+ };
14
+ export function registerAgentTools(server) {
15
+ // ------------------------------------------------------------------
16
+ // agent_list
17
+ // ------------------------------------------------------------------
18
+ server.registerTool("agent_list", {
19
+ title: "List subagents",
20
+ description: "List subagents in a scope with their name and description.",
21
+ inputSchema: {
22
+ scope: CodeScope,
23
+ ...ProjectPathField,
24
+ },
25
+ annotations: {
26
+ readOnlyHint: true,
27
+ destructiveHint: false,
28
+ idempotentHint: true,
29
+ openWorldHint: false,
30
+ },
31
+ }, async ({ scope, projectPath }) => handle(() => listAgents(scope, projectPath), (agents) => okResponse(agents.length === 0
32
+ ? `No agents found in ${scope} scope.`
33
+ : agents
34
+ .map((a) => `[${a.scope}] ${a.name}\n path: ${a.path}\n description: ${truncate(a.frontmatter.description, 120)}`)
35
+ .join("\n\n"), { agents: agents.map((a) => ({ ...a, body: truncate(a.body, 200) })) })));
36
+ // ------------------------------------------------------------------
37
+ // agent_get
38
+ // ------------------------------------------------------------------
39
+ server.registerTool("agent_get", {
40
+ title: "Get a subagent",
41
+ description: "Return a subagent's full frontmatter and body.",
42
+ inputSchema: {
43
+ scope: CodeScope,
44
+ name: z.string().min(1),
45
+ ...ProjectPathField,
46
+ },
47
+ annotations: {
48
+ readOnlyHint: true,
49
+ destructiveHint: false,
50
+ idempotentHint: true,
51
+ openWorldHint: false,
52
+ },
53
+ }, async (args) => handle(() => getAgent(args), (rec) => rec
54
+ ? okResponse(`[${rec.scope}] ${rec.name}\n path: ${rec.path}\n\n--- frontmatter ---\n${JSON.stringify(rec.frontmatter, null, 2)}\n\n--- body ---\n${rec.body}`, { agent: rec })
55
+ : okResponse(`Agent "${args.name}" not found.`, { found: false })));
56
+ // ------------------------------------------------------------------
57
+ // agent_create
58
+ // ------------------------------------------------------------------
59
+ server.registerTool("agent_create", {
60
+ title: "Create a subagent",
61
+ description: "Scaffold a new subagent markdown file. `tools` accepts either a " +
62
+ "comma-separated string or a string array; it will be written as " +
63
+ "comma-separated on disk.",
64
+ inputSchema: {
65
+ scope: CodeScope,
66
+ name: z
67
+ .string()
68
+ .regex(/^[a-z0-9][a-z0-9-]*$/, "agent name must be lowercase alphanumeric + hyphens"),
69
+ description: z.string().min(1),
70
+ model: z.string().optional(),
71
+ tools: z.union([z.string(), z.array(z.string())]).optional(),
72
+ color: z.string().optional(),
73
+ body: z.string().optional(),
74
+ overwrite: z.boolean().optional(),
75
+ ...ProjectPathField,
76
+ ...DryRunField,
77
+ },
78
+ annotations: {
79
+ readOnlyHint: false,
80
+ destructiveHint: false,
81
+ idempotentHint: false,
82
+ openWorldHint: false,
83
+ },
84
+ }, async (args) => handle(() => createAgent(args), (result) => okResponse(formatWriteResult(result, `create agent "${args.name}" at`, false), { result })));
85
+ // ------------------------------------------------------------------
86
+ // agent_update
87
+ // ------------------------------------------------------------------
88
+ server.registerTool("agent_update", {
89
+ title: "Update a subagent",
90
+ description: "Patch frontmatter fields and/or replace the body of an existing agent.",
91
+ inputSchema: {
92
+ scope: CodeScope,
93
+ name: z.string().min(1),
94
+ description: z.string().optional(),
95
+ model: z.string().optional(),
96
+ tools: z.union([z.string(), z.array(z.string())]).optional(),
97
+ color: z.string().optional(),
98
+ body: z.string().optional(),
99
+ ...ProjectPathField,
100
+ ...DryRunField,
101
+ },
102
+ annotations: {
103
+ readOnlyHint: false,
104
+ destructiveHint: false,
105
+ idempotentHint: true,
106
+ openWorldHint: false,
107
+ },
108
+ }, async (args) => handle(() => updateAgent(args), (result) => okResponse(formatWriteResult(result, `update agent "${args.name}" at`, false), { result })));
109
+ // ------------------------------------------------------------------
110
+ // agent_delete
111
+ // ------------------------------------------------------------------
112
+ server.registerTool("agent_delete", {
113
+ title: "Delete a subagent",
114
+ description: "Delete a subagent markdown file. Backed up first.",
115
+ inputSchema: {
116
+ scope: CodeScope,
117
+ name: z.string().min(1),
118
+ ...ProjectPathField,
119
+ ...DryRunField,
120
+ },
121
+ annotations: {
122
+ readOnlyHint: false,
123
+ destructiveHint: true,
124
+ idempotentHint: true,
125
+ openWorldHint: false,
126
+ },
127
+ }, async (args) => handle(() => deleteAgent(args), (result) => okResponse(formatWriteResult(result, `delete agent "${args.name}" at`, false), { result })));
128
+ }
129
+ function truncate(s, n) {
130
+ if (s.length <= n)
131
+ return s;
132
+ return s.slice(0, n - 1) + "…";
133
+ }
134
+ //# sourceMappingURL=agents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents.js","sourceRoot":"","sources":["../../src/tools/agents.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Shared helpers for tool handlers: building MCP tool responses with
3
+ * both a human-readable text block and structured JSON for modern clients.
4
+ */
5
+ export interface ToolResponse {
6
+ content: Array<{
7
+ type: "text";
8
+ text: string;
9
+ }>;
10
+ structuredContent?: Record<string, unknown>;
11
+ isError?: boolean;
12
+ [key: string]: unknown;
13
+ }
14
+ export declare function okResponse(text: string, structured?: Record<string, unknown>): ToolResponse;
15
+ export declare function errorResponse(err: unknown): ToolResponse;
16
+ /** Wrap an async handler to catch thrown errors into MCP error responses. */
17
+ export declare function handle<T>(fn: () => Promise<T>, render: (value: T) => ToolResponse): Promise<ToolResponse>;
18
+ /** Build a human-readable write-result summary line. */
19
+ export declare function formatWriteResult(result: {
20
+ path: string;
21
+ backup: string | null;
22
+ dryRun: boolean;
23
+ diff?: string;
24
+ preview?: string;
25
+ }, verb: string, restartRequired?: boolean): string;
@@ -0,0 +1,36 @@
1
+ export function okResponse(text, structured) {
2
+ return {
3
+ content: [{ type: "text", text }],
4
+ ...(structured && { structuredContent: structured }),
5
+ };
6
+ }
7
+ export function errorResponse(err) {
8
+ const msg = err instanceof Error ? err.message : String(err);
9
+ return {
10
+ content: [{ type: "text", text: `Error: ${msg}` }],
11
+ isError: true,
12
+ };
13
+ }
14
+ /** Wrap an async handler to catch thrown errors into MCP error responses. */
15
+ export function handle(fn, render) {
16
+ return fn().then(render, (err) => errorResponse(err));
17
+ }
18
+ /** Build a human-readable write-result summary line. */
19
+ export function formatWriteResult(result, verb, restartRequired = false) {
20
+ if (result.dryRun) {
21
+ const head = `[dry-run] would ${verb} ${result.path}`;
22
+ if (result.diff)
23
+ return `${head}\n\n${result.diff}`;
24
+ if (result.preview)
25
+ return `${head}\n\n${result.preview}`;
26
+ return head;
27
+ }
28
+ const lines = [`${verb} ${result.path}`];
29
+ if (result.backup)
30
+ lines.push(` backup: ${result.backup}`);
31
+ if (restartRequired) {
32
+ lines.push(" NOTE: Claude Desktop must be fully quit and relaunched for this change to take effect.");
33
+ }
34
+ return lines.join("\n");
35
+ }
36
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/tools/helpers.ts"],"names":[],"mappings":"AAWA,MAAM,UAAU,UAAU,CACxB,IAAY,EACZ,UAAoC;IAEpC,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QACjC,GAAG,CAAC,UAAU,IAAI,EAAE,iBAAiB,EAAE,UAAU,EAAE,CAAC;KACrD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAY;IACxC,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC7D,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,EAAE,EAAE,CAAC;QAClD,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,MAAM,CACpB,EAAoB,EACpB,MAAkC;IAElC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC;AACxD,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,iBAAiB,CAC/B,MAAiG,EACjG,IAAY,EACZ,eAAe,GAAG,KAAK;IAEvB,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,MAAM,IAAI,GAAG,mBAAmB,IAAI,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QACtD,IAAI,MAAM,CAAC,IAAI;YAAE,OAAO,GAAG,IAAI,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;QACpD,IAAI,MAAM,CAAC,OAAO;YAAE,OAAO,GAAG,IAAI,OAAO,MAAM,CAAC,OAAO,EAAE,CAAC;QAC1D,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IACzC,IAAI,MAAM,CAAC,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,aAAa,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5D,IAAI,eAAe,EAAE,CAAC;QACpB,KAAK,CAAC,IAAI,CACR,0FAA0F,CAC3F,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerMcpTools(server: McpServer): void;
@@ -0,0 +1,257 @@
1
+ import { z } from "zod";
2
+ import { listServers, getServer, addServer, updateServer, removeServer, setServerDisabled, } from "../services/mcp-config.js";
3
+ import { StdioServerSchema, HttpServerSchema, } from "../schemas/mcp-config.js";
4
+ import { handle, okResponse, formatWriteResult } from "./helpers.js";
5
+ const ScopeSchema = z.enum(["desktop", "user", "project"]);
6
+ const WritableScopeSchema = ScopeSchema;
7
+ const ProjectPathField = {
8
+ projectPath: z
9
+ .string()
10
+ .optional()
11
+ .describe("Absolute path to the project. Required when scope=project."),
12
+ };
13
+ const DryRunField = {
14
+ dryRun: z
15
+ .boolean()
16
+ .optional()
17
+ .describe("If true, return the diff of what would be written without touching disk."),
18
+ };
19
+ export function registerMcpTools(server) {
20
+ // ------------------------------------------------------------------
21
+ // mcp_list_servers
22
+ // ------------------------------------------------------------------
23
+ server.registerTool("mcp_list_servers", {
24
+ title: "List MCP servers",
25
+ description: "List configured MCP servers across scopes (desktop, user, project). " +
26
+ "Secret-looking env values are redacted unless revealSecrets=true.",
27
+ inputSchema: {
28
+ scope: ScopeSchema
29
+ .optional()
30
+ .describe("If omitted, list across all applicable scopes."),
31
+ ...ProjectPathField,
32
+ revealSecrets: z.boolean().optional(),
33
+ },
34
+ annotations: {
35
+ readOnlyHint: true,
36
+ destructiveHint: false,
37
+ idempotentHint: true,
38
+ openWorldHint: false,
39
+ },
40
+ }, async ({ scope, projectPath, revealSecrets }) => {
41
+ return handle(async () => {
42
+ const scopes = scope
43
+ ? [scope]
44
+ : projectPath
45
+ ? ["desktop", "user", "project"]
46
+ : ["desktop", "user"];
47
+ const all = [];
48
+ for (const s of scopes) {
49
+ try {
50
+ const list = await listServers(s, {
51
+ projectPath,
52
+ revealSecrets,
53
+ });
54
+ all.push(...list);
55
+ }
56
+ catch (err) {
57
+ // Non-fatal: scope may not be configured yet.
58
+ all.push({
59
+ scope: s,
60
+ name: "[error]",
61
+ path: "",
62
+ entry: { error: err.message },
63
+ });
64
+ }
65
+ }
66
+ return all;
67
+ }, (entries) => okResponse(entries.length === 0
68
+ ? "No MCP servers found."
69
+ : entries
70
+ .map((e) => `[${e.scope}] ${e.name}\n path: ${e.path}\n entry: ${JSON.stringify(e.entry)}`)
71
+ .join("\n\n"), { servers: entries }));
72
+ });
73
+ // ------------------------------------------------------------------
74
+ // mcp_get_server
75
+ // ------------------------------------------------------------------
76
+ server.registerTool("mcp_get_server", {
77
+ title: "Get one MCP server",
78
+ description: "Return the full config of a single MCP server by name and scope.",
79
+ inputSchema: {
80
+ scope: ScopeSchema,
81
+ name: z.string().min(1),
82
+ ...ProjectPathField,
83
+ revealSecrets: z.boolean().optional(),
84
+ },
85
+ annotations: {
86
+ readOnlyHint: true,
87
+ destructiveHint: false,
88
+ idempotentHint: true,
89
+ openWorldHint: false,
90
+ },
91
+ }, async ({ scope, name, projectPath, revealSecrets }) => handle(() => getServer({ scope, name, projectPath, revealSecrets }), (entry) => entry
92
+ ? okResponse(`[${entry.scope}] ${entry.name}\n path: ${entry.path}\n entry: ${JSON.stringify(entry.entry, null, 2)}`, { server: entry })
93
+ : okResponse(`Server "${name}" not found in scope ${scope}.`, {
94
+ found: false,
95
+ })));
96
+ // ------------------------------------------------------------------
97
+ // mcp_add_server
98
+ // ------------------------------------------------------------------
99
+ server.registerTool("mcp_add_server", {
100
+ title: "Add or replace an MCP server",
101
+ description: "Add a new MCP server entry. Provide either (command + args/env) for stdio " +
102
+ "or url + headers for HTTP transports. Use overwrite=true to replace an existing entry.",
103
+ inputSchema: {
104
+ scope: WritableScopeSchema,
105
+ name: z
106
+ .string()
107
+ .regex(/^[A-Za-z0-9_-]+$/, "server name must be alphanumeric/underscore/hyphen"),
108
+ command: z.string().optional(),
109
+ args: z.array(z.string()).optional(),
110
+ env: z.record(z.string()).optional(),
111
+ cwd: z.string().optional(),
112
+ url: z.string().url().optional(),
113
+ headers: z.record(z.string()).optional(),
114
+ overwrite: z.boolean().optional(),
115
+ ...ProjectPathField,
116
+ ...DryRunField,
117
+ },
118
+ annotations: {
119
+ readOnlyHint: false,
120
+ destructiveHint: false,
121
+ idempotentHint: false,
122
+ openWorldHint: false,
123
+ },
124
+ }, async (args) => {
125
+ return handle(async () => {
126
+ const entry = args.url
127
+ ? HttpServerSchema.parse({
128
+ url: args.url,
129
+ ...(args.headers && { headers: args.headers }),
130
+ })
131
+ : StdioServerSchema.parse({
132
+ command: args.command,
133
+ ...(args.args && { args: args.args }),
134
+ ...(args.env && { env: args.env }),
135
+ ...(args.cwd && { cwd: args.cwd }),
136
+ });
137
+ return addServer({
138
+ scope: args.scope,
139
+ name: args.name,
140
+ entry,
141
+ projectPath: args.projectPath,
142
+ overwrite: args.overwrite,
143
+ dryRun: args.dryRun,
144
+ });
145
+ }, (result) => {
146
+ const restart = args.scope === "desktop" && !result.dryRun;
147
+ return okResponse(formatWriteResult(result, `add server "${args.name}" to`, restart), { result, restartRequired: restart });
148
+ });
149
+ });
150
+ // ------------------------------------------------------------------
151
+ // mcp_update_server
152
+ // ------------------------------------------------------------------
153
+ server.registerTool("mcp_update_server", {
154
+ title: "Patch an MCP server entry",
155
+ description: "Update one or more fields of an existing MCP server entry. Only provided fields are changed.",
156
+ inputSchema: {
157
+ scope: WritableScopeSchema,
158
+ name: z.string().min(1),
159
+ command: z.string().optional(),
160
+ args: z.array(z.string()).optional(),
161
+ env: z.record(z.string()).optional(),
162
+ cwd: z.string().optional(),
163
+ url: z.string().url().optional(),
164
+ headers: z.record(z.string()).optional(),
165
+ ...ProjectPathField,
166
+ ...DryRunField,
167
+ },
168
+ annotations: {
169
+ readOnlyHint: false,
170
+ destructiveHint: false,
171
+ idempotentHint: true,
172
+ openWorldHint: false,
173
+ },
174
+ }, async (args) => handle(() => {
175
+ const patch = {};
176
+ if (args.command !== undefined)
177
+ patch.command = args.command;
178
+ if (args.args !== undefined)
179
+ patch.args = args.args;
180
+ if (args.env !== undefined)
181
+ patch.env = args.env;
182
+ if (args.cwd !== undefined)
183
+ patch.cwd = args.cwd;
184
+ if (args.url !== undefined)
185
+ patch.url = args.url;
186
+ if (args.headers !== undefined)
187
+ patch.headers = args.headers;
188
+ return updateServer({
189
+ scope: args.scope,
190
+ name: args.name,
191
+ patch: patch,
192
+ projectPath: args.projectPath,
193
+ dryRun: args.dryRun,
194
+ });
195
+ }, (result) => {
196
+ const restart = args.scope === "desktop" && !result.dryRun;
197
+ return okResponse(formatWriteResult(result, `update server "${args.name}" in`, restart), { result, restartRequired: restart });
198
+ }));
199
+ // ------------------------------------------------------------------
200
+ // mcp_remove_server
201
+ // ------------------------------------------------------------------
202
+ server.registerTool("mcp_remove_server", {
203
+ title: "Remove an MCP server",
204
+ description: "Delete an MCP server entry by name from a given scope.",
205
+ inputSchema: {
206
+ scope: WritableScopeSchema,
207
+ name: z.string().min(1),
208
+ ...ProjectPathField,
209
+ ...DryRunField,
210
+ },
211
+ annotations: {
212
+ readOnlyHint: false,
213
+ destructiveHint: true,
214
+ idempotentHint: true,
215
+ openWorldHint: false,
216
+ },
217
+ }, async (args) => handle(() => removeServer({
218
+ scope: args.scope,
219
+ name: args.name,
220
+ projectPath: args.projectPath,
221
+ dryRun: args.dryRun,
222
+ }), (result) => {
223
+ const restart = args.scope === "desktop" && !result.dryRun;
224
+ return okResponse(formatWriteResult(result, `remove server "${args.name}" from`, restart), { result, restartRequired: restart });
225
+ }));
226
+ // ------------------------------------------------------------------
227
+ // mcp_set_disabled
228
+ // ------------------------------------------------------------------
229
+ server.registerTool("mcp_set_disabled", {
230
+ title: "Enable or disable an MCP server",
231
+ description: "Toggle an MCP server on/off by setting its `disabled` flag. File is preserved.",
232
+ inputSchema: {
233
+ scope: WritableScopeSchema,
234
+ name: z.string().min(1),
235
+ disabled: z.boolean(),
236
+ ...ProjectPathField,
237
+ ...DryRunField,
238
+ },
239
+ annotations: {
240
+ readOnlyHint: false,
241
+ destructiveHint: false,
242
+ idempotentHint: true,
243
+ openWorldHint: false,
244
+ },
245
+ }, async (args) => handle(() => setServerDisabled({
246
+ scope: args.scope,
247
+ name: args.name,
248
+ disabled: args.disabled,
249
+ projectPath: args.projectPath,
250
+ dryRun: args.dryRun,
251
+ }), (result) => {
252
+ const restart = args.scope === "desktop" && !result.dryRun;
253
+ const verb = args.disabled ? "disable" : "enable";
254
+ return okResponse(formatWriteResult(result, `${verb} server "${args.name}" in`, restart), { result, restartRequired: restart });
255
+ }));
256
+ }
257
+ //# sourceMappingURL=mcp.js.map