@chamba/mcp 0.1.0 → 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.
Files changed (2) hide show
  1. package/dist/main.js +142 -85
  2. package/package.json +3 -3
package/dist/main.js CHANGED
@@ -147,17 +147,73 @@ function registerGeneratePlan(server, logger, services) {
147
147
  );
148
148
  }
149
149
 
150
+ // src/tools/get-agent-config.ts
151
+ import {
152
+ AGENT_ROLES,
153
+ buildHint,
154
+ getModel,
155
+ joinPath,
156
+ loadConfig,
157
+ resolveRole,
158
+ WORKSPACE_DIR
159
+ } from "@chamba/core";
160
+ import { z as z4 } from "zod";
161
+ var TOOL_NAME4 = "chamba_get_agent_config";
162
+ var DESCRIPTION4 = "Return the configured model + effort hint for a given agent role (orchestrator, planner, reviewer, implementer, tester, summarizer, researcher). chamba does not call any model \u2014 this is guidance the editor's own model can use to decide how to delegate. Reads ~/.chamba/config.json and ./.chamba/config.json (project overrides global); falls back to built-in defaults.";
163
+ var CONFIG_FILE = `${WORKSPACE_DIR}/config.json`;
164
+ function registerGetAgentConfig(server, logger, services) {
165
+ server.registerTool(
166
+ TOOL_NAME4,
167
+ {
168
+ title: "Get agent config",
169
+ description: DESCRIPTION4,
170
+ inputSchema: {
171
+ role: z4.enum([...AGENT_ROLES]).describe("The agent role to get a model + effort hint for.")
172
+ }
173
+ },
174
+ async ({ role }) => {
175
+ const globalPath = joinPath(services.homedir, CONFIG_FILE);
176
+ const projectPath = joinPath(services.cwd, CONFIG_FILE);
177
+ const { config, sources } = await loadConfig(services.fs, { globalPath, projectPath });
178
+ const agent = resolveRole(config, role);
179
+ const model = getModel(agent.model);
180
+ const hint = buildHint(role, agent);
181
+ const invalid = sources.find((s) => s.status === "invalid");
182
+ const warning = invalid ? `Ignored invalid config at ${invalid.path}: ${invalid.error}. Using defaults.` : void 0;
183
+ logger.info(
184
+ { tool: TOOL_NAME4, role, model: agent.model, effort: agent.effort },
185
+ "get-agent-config"
186
+ );
187
+ const structured = {
188
+ role,
189
+ model: agent.model,
190
+ effort: agent.effort,
191
+ reasoning_priority: agent.reasoning_priority,
192
+ provider: model?.provider ?? "unknown",
193
+ hint,
194
+ ...warning ? { warning } : {}
195
+ };
196
+ return {
197
+ content: [{ type: "text", text: warning ? `${hint}
198
+
199
+ \u26A0\uFE0F ${warning}` : hint }],
200
+ structuredContent: structured
201
+ };
202
+ }
203
+ );
204
+ }
205
+
150
206
  // src/tools/list-worktrees.ts
151
207
  import { WorktreeManager as WorktreeManager3 } from "@chamba/core";
152
- var TOOL_NAME4 = "chamba_list_worktrees";
153
- var DESCRIPTION4 = "List the git worktrees in the current repo (path, HEAD, branch).";
208
+ var TOOL_NAME5 = "chamba_list_worktrees";
209
+ var DESCRIPTION5 = "List the git worktrees in the current repo (path, HEAD, branch).";
154
210
  function registerListWorktrees(server, logger, services) {
155
211
  server.registerTool(
156
- TOOL_NAME4,
157
- { title: "List worktrees", description: DESCRIPTION4, inputSchema: {} },
212
+ TOOL_NAME5,
213
+ { title: "List worktrees", description: DESCRIPTION5, inputSchema: {} },
158
214
  async () => {
159
215
  const worktrees = await new WorktreeManager3(services.process).list(services.cwd);
160
- logger.info({ tool: TOOL_NAME4, count: worktrees.length }, "listed worktrees");
216
+ logger.info({ tool: TOOL_NAME5, count: worktrees.length }, "listed worktrees");
161
217
  const text = worktrees.length === 0 ? "No worktrees found (or not a git repo)." : worktrees.map((w) => `- ${w.path}${w.branch ? ` [${w.branch}]` : ""}`).join("\n");
162
218
  return {
163
219
  content: [{ type: "text", text }],
@@ -169,18 +225,18 @@ function registerListWorktrees(server, logger, services) {
169
225
 
170
226
  // src/tools/load-context.ts
171
227
  import { ContextBuilder, ObsidianDetector, WorkspaceScanner as WorkspaceScanner2 } from "@chamba/core";
172
- import { z as z4 } from "zod";
173
- var TOOL_NAME5 = "chamba_load_context";
174
- var DESCRIPTION5 = "Load context for a task: a summary of the workspace plus, when an Obsidian vault is available, the notes most relevant to the task (keyword search). Returns a markdown block the model can reason over before planning.";
228
+ import { z as z5 } from "zod";
229
+ var TOOL_NAME6 = "chamba_load_context";
230
+ var DESCRIPTION6 = "Load context for a task: a summary of the workspace plus, when an Obsidian vault is available, the notes most relevant to the task (keyword search). Returns a markdown block the model can reason over before planning.";
175
231
  function registerLoadContext(server, logger, services) {
176
232
  server.registerTool(
177
- TOOL_NAME5,
233
+ TOOL_NAME6,
178
234
  {
179
235
  title: "Load context",
180
- description: DESCRIPTION5,
236
+ description: DESCRIPTION6,
181
237
  inputSchema: {
182
- task: z4.string().describe("The task you are about to work on."),
183
- includeObsidian: z4.boolean().optional().describe("Search the Obsidian vault for relevant notes (default true).")
238
+ task: z5.string().describe("The task you are about to work on."),
239
+ includeObsidian: z5.boolean().optional().describe("Search the Obsidian vault for relevant notes (default true).")
184
240
  }
185
241
  },
186
242
  async ({ task, includeObsidian }) => {
@@ -195,7 +251,7 @@ function registerLoadContext(server, logger, services) {
195
251
  }
196
252
  const built = await new ContextBuilder(services.fs).build({ workspace, task, vaultPath });
197
253
  logger.info(
198
- { tool: TOOL_NAME5, vault: vaultPath ?? null, notes: built.relevantNotes.length },
254
+ { tool: TOOL_NAME6, vault: vaultPath ?? null, notes: built.relevantNotes.length },
199
255
  "context built"
200
256
  );
201
257
  return { content: [{ type: "text", text: built.context }] };
@@ -205,23 +261,23 @@ function registerLoadContext(server, logger, services) {
205
261
 
206
262
  // src/tools/recall.ts
207
263
  import { FilesystemMemoryStore } from "@chamba/core";
208
- import { z as z5 } from "zod";
209
- var TOOL_NAME6 = "chamba_recall";
210
- var DESCRIPTION6 = "Search persisted memories (case-insensitive substring over key, tags and content) and return the matches with their paths and content.";
264
+ import { z as z6 } from "zod";
265
+ var TOOL_NAME7 = "chamba_recall";
266
+ var DESCRIPTION7 = "Search persisted memories (case-insensitive substring over key, tags and content) and return the matches with their paths and content.";
211
267
  function registerRecall(server, logger, services) {
212
268
  server.registerTool(
213
- TOOL_NAME6,
269
+ TOOL_NAME7,
214
270
  {
215
271
  title: "Recall",
216
- description: DESCRIPTION6,
272
+ description: DESCRIPTION7,
217
273
  inputSchema: {
218
- query: z5.string().describe("Keywords to search for.")
274
+ query: z6.string().describe("Keywords to search for.")
219
275
  }
220
276
  },
221
277
  async ({ query }) => {
222
278
  const store = new FilesystemMemoryStore(services.fs, services.clock, services.cwd);
223
279
  const matches = await store.recall(query);
224
- logger.info({ tool: TOOL_NAME6, query, matches: matches.length }, "recall");
280
+ logger.info({ tool: TOOL_NAME7, query, matches: matches.length }, "recall");
225
281
  const text = matches.length === 0 ? `No memories matched "${query}".` : matches.map((m) => `### ${m.key} (\`${m.path}\`)
226
282
  ${m.content}`).join("\n\n");
227
283
  return {
@@ -241,25 +297,25 @@ ${m.content}`).join("\n\n");
241
297
 
242
298
  // src/tools/remember.ts
243
299
  import { FilesystemMemoryStore as FilesystemMemoryStore2 } from "@chamba/core";
244
- import { z as z6 } from "zod";
245
- var TOOL_NAME7 = "chamba_remember";
246
- var DESCRIPTION7 = "Persist a piece of knowledge across sessions as an editable markdown file under `.chamba/memory/<key>.md`. Re-remembering an existing key appends a timestamped section instead of overwriting.";
300
+ import { z as z7 } from "zod";
301
+ var TOOL_NAME8 = "chamba_remember";
302
+ var DESCRIPTION8 = "Persist a piece of knowledge across sessions as an editable markdown file under `.chamba/memory/<key>.md`. Re-remembering an existing key appends a timestamped section instead of overwriting.";
247
303
  function registerRemember(server, logger, services) {
248
304
  server.registerTool(
249
- TOOL_NAME7,
305
+ TOOL_NAME8,
250
306
  {
251
307
  title: "Remember",
252
- description: DESCRIPTION7,
308
+ description: DESCRIPTION8,
253
309
  inputSchema: {
254
- key: z6.string().describe('Short identifier, e.g. "auth-decisions".'),
255
- content: z6.string().describe("What to remember (markdown)."),
256
- tags: z6.array(z6.string()).optional().describe("Optional tags for search.")
310
+ key: z7.string().describe('Short identifier, e.g. "auth-decisions".'),
311
+ content: z7.string().describe("What to remember (markdown)."),
312
+ tags: z7.array(z7.string()).optional().describe("Optional tags for search.")
257
313
  }
258
314
  },
259
315
  async ({ key, content, tags }) => {
260
316
  const store = new FilesystemMemoryStore2(services.fs, services.clock, services.cwd);
261
317
  const memory = await store.remember({ key, content, tags });
262
- logger.info({ tool: TOOL_NAME7, key, path: memory.path }, "memory saved");
318
+ logger.info({ tool: TOOL_NAME8, key, path: memory.path }, "memory saved");
263
319
  return {
264
320
  content: [{ type: "text", text: `Saved memory '${key}' to ${memory.path}` }],
265
321
  structuredContent: { saved: true, path: memory.path }
@@ -270,38 +326,38 @@ function registerRemember(server, logger, services) {
270
326
 
271
327
  // src/tools/review-plan.ts
272
328
  import { Reviewer, WorkspaceScanner as WorkspaceScanner3 } from "@chamba/core";
273
- import { z as z7 } from "zod";
274
- var TOOL_NAME8 = "chamba_review_plan";
275
- var DESCRIPTION8 = "Review a plan with programmatic heuristics (NO LLM): checks for acceptance criteria, tests, subtasks with assigned workers, concrete descriptions, files outside the workspace, and risk assessment for sensitive areas. Returns { approved, issues, suggestions, riskFlags }.";
329
+ import { z as z8 } from "zod";
330
+ var TOOL_NAME9 = "chamba_review_plan";
331
+ var DESCRIPTION9 = "Review a plan with programmatic heuristics (NO LLM): checks for acceptance criteria, tests, subtasks with assigned workers, concrete descriptions, files outside the workspace, and risk assessment for sensitive areas. Returns { approved, issues, suggestions, riskFlags }.";
276
332
  function registerReviewPlan(server, logger, services) {
277
333
  server.registerTool(
278
- TOOL_NAME8,
334
+ TOOL_NAME9,
279
335
  {
280
336
  title: "Review plan",
281
- description: DESCRIPTION8,
337
+ description: DESCRIPTION9,
282
338
  inputSchema: {
283
- plan: z7.string().describe("The plan markdown to review."),
284
- task: z7.string().describe("The task the plan is for."),
285
- context: z7.string().optional().describe("Context from chamba_load_context, if any.")
339
+ plan: z8.string().describe("The plan markdown to review."),
340
+ task: z8.string().describe("The task the plan is for."),
341
+ context: z8.string().optional().describe("Context from chamba_load_context, if any.")
286
342
  },
287
343
  outputSchema: {
288
- approved: z7.boolean(),
289
- issues: z7.array(
290
- z7.object({
291
- code: z7.string(),
292
- severity: z7.enum(["error", "warning"]),
293
- message: z7.string()
344
+ approved: z8.boolean(),
345
+ issues: z8.array(
346
+ z8.object({
347
+ code: z8.string(),
348
+ severity: z8.enum(["error", "warning"]),
349
+ message: z8.string()
294
350
  })
295
351
  ),
296
- suggestions: z7.array(z7.string()),
297
- riskFlags: z7.array(z7.string())
352
+ suggestions: z8.array(z8.string()),
353
+ riskFlags: z8.array(z8.string())
298
354
  }
299
355
  },
300
356
  async ({ plan, task, context }) => {
301
357
  const workspace = await new WorkspaceScanner3(services.fs).scan(services.cwd);
302
358
  const review = new Reviewer().review({ plan, task, context, workspace });
303
359
  logger.info(
304
- { tool: TOOL_NAME8, approved: review.approved, issues: review.issues.length },
360
+ { tool: TOOL_NAME9, approved: review.approved, issues: review.issues.length },
305
361
  "plan reviewed"
306
362
  );
307
363
  const verdict = review.approved ? "\u2705 approved" : "\u274C changes requested";
@@ -326,20 +382,20 @@ ${review.suggestions.map((s) => `- ${s}`).join("\n")}` : ""
326
382
 
327
383
  // src/tools/summarize-to-vault.ts
328
384
  import { ObsidianDetector as ObsidianDetector2, VaultWriter } from "@chamba/core";
329
- import { z as z8 } from "zod";
330
- var TOOL_NAME9 = "chamba_summarize_to_vault";
385
+ import { z as z9 } from "zod";
386
+ var TOOL_NAME10 = "chamba_summarize_to_vault";
331
387
  var NO_VAULT_ERROR = "No Obsidian vault configured. Set CHAMBA_OBSIDIAN_VAULT_PATH or use the obsidian-mcp server";
332
- var DESCRIPTION9 = "Write a structured summary note to the Obsidian vault under `proyectos/<date>-<slug>.md` with valid YAML frontmatter. Fails clearly if no vault is configured.";
388
+ var DESCRIPTION10 = "Write a structured summary note to the Obsidian vault under `proyectos/<date>-<slug>.md` with valid YAML frontmatter. Fails clearly if no vault is configured.";
333
389
  function registerSummarizeToVault(server, logger, services) {
334
390
  server.registerTool(
335
- TOOL_NAME9,
391
+ TOOL_NAME10,
336
392
  {
337
393
  title: "Summarize to vault",
338
- description: DESCRIPTION9,
394
+ description: DESCRIPTION10,
339
395
  inputSchema: {
340
- title: z8.string().describe("Note title."),
341
- content: z8.string().describe("Markdown body (summary, plan, decisions, next steps)."),
342
- projectSlug: z8.string().optional().describe("Optional slug for the filename.")
396
+ title: z9.string().describe("Note title."),
397
+ content: z9.string().describe("Markdown body (summary, plan, decisions, next steps)."),
398
+ projectSlug: z9.string().optional().describe("Optional slug for the filename.")
343
399
  }
344
400
  },
345
401
  async ({ title, content, projectSlug }) => {
@@ -348,7 +404,7 @@ function registerSummarizeToVault(server, logger, services) {
348
404
  searchRoots: obsidianSearchRoots(services)
349
405
  });
350
406
  if (!detection.found || !detection.path) {
351
- logger.info({ tool: TOOL_NAME9 }, "no vault configured");
407
+ logger.info({ tool: TOOL_NAME10 }, "no vault configured");
352
408
  return { isError: true, content: [{ type: "text", text: NO_VAULT_ERROR }] };
353
409
  }
354
410
  const writer = new VaultWriter(services.fs, services.clock);
@@ -358,7 +414,7 @@ function registerSummarizeToVault(server, logger, services) {
358
414
  content,
359
415
  projectSlug
360
416
  });
361
- logger.info({ tool: TOOL_NAME9, notePath }, "note written to vault");
417
+ logger.info({ tool: TOOL_NAME10, notePath }, "note written to vault");
362
418
  return { content: [{ type: "text", text: `Wrote note to ${notePath}` }] };
363
419
  }
364
420
  );
@@ -366,31 +422,31 @@ function registerSummarizeToVault(server, logger, services) {
366
422
 
367
423
  // src/tools/workspace-init.ts
368
424
  import {
369
- joinPath,
425
+ joinPath as joinPath2,
370
426
  renderWorkspaceMarkdown,
371
- WORKSPACE_DIR,
427
+ WORKSPACE_DIR as WORKSPACE_DIR2,
372
428
  WORKSPACE_RELATIVE_PATH,
373
429
  WorkspaceScanner as WorkspaceScanner4
374
430
  } from "@chamba/core";
375
- import { z as z9 } from "zod";
376
- var TOOL_NAME10 = "chamba_workspace_init";
377
- var DESCRIPTION10 = "Scan the workspace and generate `.chamba/workspace.md` (description, languages, framework, conventions, active projects, folder map). Respects .gitignore/.dockerignore and never reads node_modules or binaries. If the file already exists it is NOT overwritten \u2014 its current contents are returned so the model/user decides what to do.";
431
+ import { z as z10 } from "zod";
432
+ var TOOL_NAME11 = "chamba_workspace_init";
433
+ var DESCRIPTION11 = "Scan the workspace and generate `.chamba/workspace.md` (description, languages, framework, conventions, active projects, folder map). Respects .gitignore/.dockerignore and never reads node_modules or binaries. If the file already exists it is NOT overwritten \u2014 its current contents are returned so the model/user decides what to do.";
378
434
  function registerWorkspaceInit(server, logger, services) {
379
435
  server.registerTool(
380
- TOOL_NAME10,
436
+ TOOL_NAME11,
381
437
  {
382
438
  title: "Init workspace",
383
- description: DESCRIPTION10,
439
+ description: DESCRIPTION11,
384
440
  inputSchema: {
385
- root: z9.string().optional().describe("Workspace root to scan. Defaults to the directory chamba runs in.")
441
+ root: z10.string().optional().describe("Workspace root to scan. Defaults to the directory chamba runs in.")
386
442
  }
387
443
  },
388
444
  async ({ root }) => {
389
445
  const workspaceRoot = root ?? services.cwd;
390
- const wsPath = joinPath(workspaceRoot, WORKSPACE_RELATIVE_PATH);
446
+ const wsPath = joinPath2(workspaceRoot, WORKSPACE_RELATIVE_PATH);
391
447
  if (await services.fs.exists(wsPath)) {
392
448
  const currentContents = await services.fs.readFile(wsPath);
393
- logger.info({ tool: TOOL_NAME10, wsPath }, "workspace.md already exists, not overwriting");
449
+ logger.info({ tool: TOOL_NAME11, wsPath }, "workspace.md already exists, not overwriting");
394
450
  return {
395
451
  content: [
396
452
  {
@@ -407,10 +463,10 @@ ${currentContents}`
407
463
  const scanner = new WorkspaceScanner4(services.fs);
408
464
  const workspace = await scanner.scan(workspaceRoot);
409
465
  const markdown = renderWorkspaceMarkdown(workspace);
410
- await services.fs.mkdir(joinPath(workspaceRoot, WORKSPACE_DIR));
466
+ await services.fs.mkdir(joinPath2(workspaceRoot, WORKSPACE_DIR2));
411
467
  await services.fs.writeFile(wsPath, markdown);
412
468
  logger.info(
413
- { tool: TOOL_NAME10, wsPath, projects: workspace.projects.length },
469
+ { tool: TOOL_NAME11, wsPath, projects: workspace.projects.length },
414
470
  "workspace.md created"
415
471
  );
416
472
  return {
@@ -430,26 +486,26 @@ ${markdown}`
430
486
  // src/tools/workspace-reload.ts
431
487
  import {
432
488
  diffLines,
433
- joinPath as joinPath2,
489
+ joinPath as joinPath3,
434
490
  renderWorkspaceMarkdown as renderWorkspaceMarkdown2,
435
491
  textsEqual,
436
492
  WORKSPACE_RELATIVE_PATH as WORKSPACE_RELATIVE_PATH2,
437
493
  WorkspaceScanner as WorkspaceScanner5
438
494
  } from "@chamba/core";
439
- var TOOL_NAME11 = "chamba_workspace_reload";
440
- var DESCRIPTION11 = "Re-scan the workspace and return a diff against the current `.chamba/workspace.md`. NEVER overwrites the file \u2014 the user may have hand-edited it. The model decides whether to apply changes.";
495
+ var TOOL_NAME12 = "chamba_workspace_reload";
496
+ var DESCRIPTION12 = "Re-scan the workspace and return a diff against the current `.chamba/workspace.md`. NEVER overwrites the file \u2014 the user may have hand-edited it. The model decides whether to apply changes.";
441
497
  function registerWorkspaceReload(server, logger, services) {
442
498
  server.registerTool(
443
- TOOL_NAME11,
499
+ TOOL_NAME12,
444
500
  {
445
501
  title: "Reload workspace",
446
- description: DESCRIPTION11,
502
+ description: DESCRIPTION12,
447
503
  inputSchema: {}
448
504
  },
449
505
  async () => {
450
- const wsPath = joinPath2(services.cwd, WORKSPACE_RELATIVE_PATH2);
506
+ const wsPath = joinPath3(services.cwd, WORKSPACE_RELATIVE_PATH2);
451
507
  if (!await services.fs.exists(wsPath)) {
452
- logger.info({ tool: TOOL_NAME11, wsPath }, "no workspace.md to reload");
508
+ logger.info({ tool: TOOL_NAME12, wsPath }, "no workspace.md to reload");
453
509
  return {
454
510
  content: [
455
511
  {
@@ -463,7 +519,7 @@ function registerWorkspaceReload(server, logger, services) {
463
519
  const scanner = new WorkspaceScanner5(services.fs);
464
520
  const rescanned = renderWorkspaceMarkdown2(await scanner.scan(services.cwd));
465
521
  if (textsEqual(current, rescanned)) {
466
- logger.info({ tool: TOOL_NAME11, wsPath }, "workspace.md up to date");
522
+ logger.info({ tool: TOOL_NAME12, wsPath }, "workspace.md up to date");
467
523
  return {
468
524
  content: [
469
525
  {
@@ -473,7 +529,7 @@ function registerWorkspaceReload(server, logger, services) {
473
529
  ]
474
530
  };
475
531
  }
476
- logger.info({ tool: TOOL_NAME11, wsPath }, "workspace.md differs from re-scan");
532
+ logger.info({ tool: TOOL_NAME12, wsPath }, "workspace.md differs from re-scan");
477
533
  return {
478
534
  content: [
479
535
  {
@@ -491,25 +547,25 @@ ${diffLines(current, rescanned)}
491
547
  }
492
548
 
493
549
  // src/tools/workspace-show.ts
494
- import { joinPath as joinPath3, WORKSPACE_RELATIVE_PATH as WORKSPACE_RELATIVE_PATH3 } from "@chamba/core";
495
- var TOOL_NAME12 = "chamba_workspace_show";
496
- var DESCRIPTION12 = "Show the current workspace map. Reads `.chamba/workspace.md` from the workspace root and returns its contents. If no workspace file exists yet, says so \u2014 the model can then run chamba_workspace_init to create one.";
550
+ import { joinPath as joinPath4, WORKSPACE_RELATIVE_PATH as WORKSPACE_RELATIVE_PATH3 } from "@chamba/core";
551
+ var TOOL_NAME13 = "chamba_workspace_show";
552
+ var DESCRIPTION13 = "Show the current workspace map. Reads `.chamba/workspace.md` from the workspace root and returns its contents. If no workspace file exists yet, says so \u2014 the model can then run chamba_workspace_init to create one.";
497
553
  function registerWorkspaceShow(server, logger, services) {
498
554
  server.registerTool(
499
- TOOL_NAME12,
555
+ TOOL_NAME13,
500
556
  {
501
557
  title: "Show workspace",
502
- description: DESCRIPTION12,
558
+ description: DESCRIPTION13,
503
559
  inputSchema: {}
504
560
  },
505
561
  async () => {
506
- const path = joinPath3(services.cwd, WORKSPACE_RELATIVE_PATH3);
562
+ const path = joinPath4(services.cwd, WORKSPACE_RELATIVE_PATH3);
507
563
  try {
508
564
  const contents = await services.fs.readFile(path);
509
- logger.info({ tool: TOOL_NAME12, path }, "workspace.md read");
565
+ logger.info({ tool: TOOL_NAME13, path }, "workspace.md read");
510
566
  return { content: [{ type: "text", text: contents }] };
511
567
  } catch {
512
- logger.info({ tool: TOOL_NAME12, path }, "no workspace.md found");
568
+ logger.info({ tool: TOOL_NAME13, path }, "no workspace.md found");
513
569
  return {
514
570
  content: [
515
571
  {
@@ -540,6 +596,7 @@ function createServer(logger, services = createNodeServices()) {
540
596
  registerCleanupWorktree(server, logger, services);
541
597
  registerRemember(server, logger, services);
542
598
  registerRecall(server, logger, services);
599
+ registerGetAgentConfig(server, logger, services);
543
600
  return server;
544
601
  }
545
602
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chamba/mcp",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "chamba MCP server — orchestration, workspace, worktree and Obsidian tools for any MCP-capable editor",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -36,8 +36,8 @@
36
36
  "@modelcontextprotocol/sdk": "^1.12.0",
37
37
  "pino": "^9.0.0",
38
38
  "zod": "^3.23.0",
39
- "@chamba/core": "0.1.0",
40
- "@chamba/adapters": "0.1.0"
39
+ "@chamba/adapters": "0.2.0",
40
+ "@chamba/core": "0.2.0"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/node": "^22.0.0",