@chamba/mcp 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.js +81 -22
- package/package.json +3 -3
package/dist/main.js
CHANGED
|
@@ -401,10 +401,11 @@ function registerLoadContext(server, logger, services) {
|
|
|
401
401
|
description: DESCRIPTION8,
|
|
402
402
|
inputSchema: {
|
|
403
403
|
task: z7.string().describe("The task you are about to work on."),
|
|
404
|
-
includeObsidian: z7.boolean().optional().describe("Search the Obsidian vault for relevant notes (default true).")
|
|
404
|
+
includeObsidian: z7.boolean().optional().describe("Search the Obsidian vault for relevant notes (default true)."),
|
|
405
|
+
includeRules: z7.boolean().optional().describe("Include each repo's coding rules across editors (default true).")
|
|
405
406
|
}
|
|
406
407
|
},
|
|
407
|
-
async ({ task, includeObsidian }) => {
|
|
408
|
+
async ({ task, includeObsidian, includeRules }) => {
|
|
408
409
|
const workspace = await new WorkspaceScanner2(services.fs).scan(services.cwd);
|
|
409
410
|
let vaultPath;
|
|
410
411
|
if (includeObsidian !== false) {
|
|
@@ -414,7 +415,12 @@ function registerLoadContext(server, logger, services) {
|
|
|
414
415
|
});
|
|
415
416
|
if (detection.found) vaultPath = detection.path;
|
|
416
417
|
}
|
|
417
|
-
const built = await new ContextBuilder(services.fs).build({
|
|
418
|
+
const built = await new ContextBuilder(services.fs).build({
|
|
419
|
+
workspace,
|
|
420
|
+
task,
|
|
421
|
+
vaultPath,
|
|
422
|
+
includeRules
|
|
423
|
+
});
|
|
418
424
|
logger.info(
|
|
419
425
|
{ tool: TOOL_NAME8, vault: vaultPath ?? null, notes: built.relevantNotes.length },
|
|
420
426
|
"context built"
|
|
@@ -585,6 +591,58 @@ function registerSummarizeToVault(server, logger, services) {
|
|
|
585
591
|
);
|
|
586
592
|
}
|
|
587
593
|
|
|
594
|
+
// src/tools/vault-status.ts
|
|
595
|
+
import { listVaultNotes, ObsidianDetector as ObsidianDetector3 } from "@chamba/core";
|
|
596
|
+
var TOOL_NAME13 = "chamba_vault_status";
|
|
597
|
+
var DESCRIPTION13 = "Diagnose the Obsidian vault connection: the resolved vault path, whether it was found, and the markdown notes chamba can actually see (the same set `chamba_load_context` searches). Use this to confirm the vault points at the vault root (the folder containing `.obsidian`), not at `.obsidian` itself.";
|
|
598
|
+
var MAX_LISTED = 50;
|
|
599
|
+
function registerVaultStatus(server, logger, services) {
|
|
600
|
+
server.registerTool(
|
|
601
|
+
TOOL_NAME13,
|
|
602
|
+
{
|
|
603
|
+
title: "Vault status",
|
|
604
|
+
description: DESCRIPTION13,
|
|
605
|
+
inputSchema: {}
|
|
606
|
+
},
|
|
607
|
+
async () => {
|
|
608
|
+
const detection = await new ObsidianDetector3(services.fs).detect({
|
|
609
|
+
explicitPath: services.obsidianVaultPath,
|
|
610
|
+
searchRoots: obsidianSearchRoots(services)
|
|
611
|
+
});
|
|
612
|
+
if (!detection.found || !detection.path) {
|
|
613
|
+
const text2 = `No Obsidian vault found.
|
|
614
|
+
Set CHAMBA_OBSIDIAN_VAULT_PATH to your vault root (the folder containing .obsidian), or place the vault under a common location. Searched: ${obsidianSearchRoots(services).join(", ")}.`;
|
|
615
|
+
logger.info({ tool: TOOL_NAME13, found: false }, "vault-status");
|
|
616
|
+
return {
|
|
617
|
+
content: [{ type: "text", text: text2 }],
|
|
618
|
+
structuredContent: { found: false }
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
const paths = await listVaultNotes(services.fs, detection.path);
|
|
622
|
+
const names = paths.map((p) => p.slice(detection.path?.length ?? 0).replace(/^\/+/, ""));
|
|
623
|
+
const source = services.obsidianVaultPath ? "CHAMBA_OBSIDIAN_VAULT_PATH" : "autodetected";
|
|
624
|
+
logger.info({ tool: TOOL_NAME13, vault: detection.path, notes: names.length }, "vault-status");
|
|
625
|
+
const shown = names.slice(0, MAX_LISTED);
|
|
626
|
+
const more = names.length > MAX_LISTED ? `
|
|
627
|
+
\u2026and ${names.length - MAX_LISTED} more` : "";
|
|
628
|
+
const text = `Vault: ${detection.path} (${source})
|
|
629
|
+
Notes chamba can see: ${names.length}
|
|
630
|
+
|
|
631
|
+
${shown.map((n) => `- ${n}`).join("\n")}${more}` + (names.length === 0 ? "\n\n\u26A0\uFE0F No notes found. If your path ends in `.obsidian`, point it at the parent folder instead." : "");
|
|
632
|
+
return {
|
|
633
|
+
content: [{ type: "text", text }],
|
|
634
|
+
structuredContent: {
|
|
635
|
+
found: true,
|
|
636
|
+
vaultPath: detection.path,
|
|
637
|
+
source,
|
|
638
|
+
noteCount: names.length,
|
|
639
|
+
notes: shown
|
|
640
|
+
}
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
);
|
|
644
|
+
}
|
|
645
|
+
|
|
588
646
|
// src/tools/workspace-init.ts
|
|
589
647
|
import {
|
|
590
648
|
joinPath as joinPath4,
|
|
@@ -594,14 +652,14 @@ import {
|
|
|
594
652
|
WorkspaceScanner as WorkspaceScanner4
|
|
595
653
|
} from "@chamba/core";
|
|
596
654
|
import { z as z12 } from "zod";
|
|
597
|
-
var
|
|
598
|
-
var
|
|
655
|
+
var TOOL_NAME14 = "chamba_workspace_init";
|
|
656
|
+
var DESCRIPTION14 = "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.";
|
|
599
657
|
function registerWorkspaceInit(server, logger, services) {
|
|
600
658
|
server.registerTool(
|
|
601
|
-
|
|
659
|
+
TOOL_NAME14,
|
|
602
660
|
{
|
|
603
661
|
title: "Init workspace",
|
|
604
|
-
description:
|
|
662
|
+
description: DESCRIPTION14,
|
|
605
663
|
inputSchema: {
|
|
606
664
|
root: z12.string().optional().describe("Workspace root to scan. Defaults to the directory chamba runs in.")
|
|
607
665
|
}
|
|
@@ -611,7 +669,7 @@ function registerWorkspaceInit(server, logger, services) {
|
|
|
611
669
|
const wsPath = joinPath4(workspaceRoot, WORKSPACE_RELATIVE_PATH);
|
|
612
670
|
if (await services.fs.exists(wsPath)) {
|
|
613
671
|
const currentContents = await services.fs.readFile(wsPath);
|
|
614
|
-
logger.info({ tool:
|
|
672
|
+
logger.info({ tool: TOOL_NAME14, wsPath }, "workspace.md already exists, not overwriting");
|
|
615
673
|
return {
|
|
616
674
|
content: [
|
|
617
675
|
{
|
|
@@ -631,7 +689,7 @@ ${currentContents}`
|
|
|
631
689
|
await services.fs.mkdir(joinPath4(workspaceRoot, WORKSPACE_DIR4));
|
|
632
690
|
await services.fs.writeFile(wsPath, markdown);
|
|
633
691
|
logger.info(
|
|
634
|
-
{ tool:
|
|
692
|
+
{ tool: TOOL_NAME14, wsPath, projects: workspace.projects.length },
|
|
635
693
|
"workspace.md created"
|
|
636
694
|
);
|
|
637
695
|
return {
|
|
@@ -657,20 +715,20 @@ import {
|
|
|
657
715
|
WORKSPACE_RELATIVE_PATH as WORKSPACE_RELATIVE_PATH2,
|
|
658
716
|
WorkspaceScanner as WorkspaceScanner5
|
|
659
717
|
} from "@chamba/core";
|
|
660
|
-
var
|
|
661
|
-
var
|
|
718
|
+
var TOOL_NAME15 = "chamba_workspace_reload";
|
|
719
|
+
var DESCRIPTION15 = "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.";
|
|
662
720
|
function registerWorkspaceReload(server, logger, services) {
|
|
663
721
|
server.registerTool(
|
|
664
|
-
|
|
722
|
+
TOOL_NAME15,
|
|
665
723
|
{
|
|
666
724
|
title: "Reload workspace",
|
|
667
|
-
description:
|
|
725
|
+
description: DESCRIPTION15,
|
|
668
726
|
inputSchema: {}
|
|
669
727
|
},
|
|
670
728
|
async () => {
|
|
671
729
|
const wsPath = joinPath5(services.cwd, WORKSPACE_RELATIVE_PATH2);
|
|
672
730
|
if (!await services.fs.exists(wsPath)) {
|
|
673
|
-
logger.info({ tool:
|
|
731
|
+
logger.info({ tool: TOOL_NAME15, wsPath }, "no workspace.md to reload");
|
|
674
732
|
return {
|
|
675
733
|
content: [
|
|
676
734
|
{
|
|
@@ -684,7 +742,7 @@ function registerWorkspaceReload(server, logger, services) {
|
|
|
684
742
|
const scanner = new WorkspaceScanner5(services.fs);
|
|
685
743
|
const rescanned = renderWorkspaceMarkdown2(await scanner.scan(services.cwd));
|
|
686
744
|
if (textsEqual(current, rescanned)) {
|
|
687
|
-
logger.info({ tool:
|
|
745
|
+
logger.info({ tool: TOOL_NAME15, wsPath }, "workspace.md up to date");
|
|
688
746
|
return {
|
|
689
747
|
content: [
|
|
690
748
|
{
|
|
@@ -694,7 +752,7 @@ function registerWorkspaceReload(server, logger, services) {
|
|
|
694
752
|
]
|
|
695
753
|
};
|
|
696
754
|
}
|
|
697
|
-
logger.info({ tool:
|
|
755
|
+
logger.info({ tool: TOOL_NAME15, wsPath }, "workspace.md differs from re-scan");
|
|
698
756
|
return {
|
|
699
757
|
content: [
|
|
700
758
|
{
|
|
@@ -713,24 +771,24 @@ ${diffLines(current, rescanned)}
|
|
|
713
771
|
|
|
714
772
|
// src/tools/workspace-show.ts
|
|
715
773
|
import { joinPath as joinPath6, WORKSPACE_RELATIVE_PATH as WORKSPACE_RELATIVE_PATH3 } from "@chamba/core";
|
|
716
|
-
var
|
|
717
|
-
var
|
|
774
|
+
var TOOL_NAME16 = "chamba_workspace_show";
|
|
775
|
+
var DESCRIPTION16 = "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.";
|
|
718
776
|
function registerWorkspaceShow(server, logger, services) {
|
|
719
777
|
server.registerTool(
|
|
720
|
-
|
|
778
|
+
TOOL_NAME16,
|
|
721
779
|
{
|
|
722
780
|
title: "Show workspace",
|
|
723
|
-
description:
|
|
781
|
+
description: DESCRIPTION16,
|
|
724
782
|
inputSchema: {}
|
|
725
783
|
},
|
|
726
784
|
async () => {
|
|
727
785
|
const path = joinPath6(services.cwd, WORKSPACE_RELATIVE_PATH3);
|
|
728
786
|
try {
|
|
729
787
|
const contents = await services.fs.readFile(path);
|
|
730
|
-
logger.info({ tool:
|
|
788
|
+
logger.info({ tool: TOOL_NAME16, path }, "workspace.md read");
|
|
731
789
|
return { content: [{ type: "text", text: contents }] };
|
|
732
790
|
} catch {
|
|
733
|
-
logger.info({ tool:
|
|
791
|
+
logger.info({ tool: TOOL_NAME16, path }, "no workspace.md found");
|
|
734
792
|
return {
|
|
735
793
|
content: [
|
|
736
794
|
{
|
|
@@ -754,6 +812,7 @@ function createServer(logger, services = createNodeServices()) {
|
|
|
754
812
|
registerWorkspaceReload(server, logger, services);
|
|
755
813
|
registerLoadContext(server, logger, services);
|
|
756
814
|
registerSummarizeToVault(server, logger, services);
|
|
815
|
+
registerVaultStatus(server, logger, services);
|
|
757
816
|
registerGeneratePlan(server, logger, services);
|
|
758
817
|
registerReviewPlan(server, logger, services);
|
|
759
818
|
registerCreateWorktree(server, logger, services);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chamba/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.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/adapters": "0.
|
|
40
|
-
"@chamba/core": "0.
|
|
39
|
+
"@chamba/adapters": "0.4.0",
|
|
40
|
+
"@chamba/core": "0.4.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/node": "^22.0.0",
|