@chamba/mcp 0.3.1 → 0.3.2
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 +72 -19
- package/package.json +3 -3
package/dist/main.js
CHANGED
|
@@ -585,6 +585,58 @@ function registerSummarizeToVault(server, logger, services) {
|
|
|
585
585
|
);
|
|
586
586
|
}
|
|
587
587
|
|
|
588
|
+
// src/tools/vault-status.ts
|
|
589
|
+
import { listVaultNotes, ObsidianDetector as ObsidianDetector3 } from "@chamba/core";
|
|
590
|
+
var TOOL_NAME13 = "chamba_vault_status";
|
|
591
|
+
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.";
|
|
592
|
+
var MAX_LISTED = 50;
|
|
593
|
+
function registerVaultStatus(server, logger, services) {
|
|
594
|
+
server.registerTool(
|
|
595
|
+
TOOL_NAME13,
|
|
596
|
+
{
|
|
597
|
+
title: "Vault status",
|
|
598
|
+
description: DESCRIPTION13,
|
|
599
|
+
inputSchema: {}
|
|
600
|
+
},
|
|
601
|
+
async () => {
|
|
602
|
+
const detection = await new ObsidianDetector3(services.fs).detect({
|
|
603
|
+
explicitPath: services.obsidianVaultPath,
|
|
604
|
+
searchRoots: obsidianSearchRoots(services)
|
|
605
|
+
});
|
|
606
|
+
if (!detection.found || !detection.path) {
|
|
607
|
+
const text2 = `No Obsidian vault found.
|
|
608
|
+
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(", ")}.`;
|
|
609
|
+
logger.info({ tool: TOOL_NAME13, found: false }, "vault-status");
|
|
610
|
+
return {
|
|
611
|
+
content: [{ type: "text", text: text2 }],
|
|
612
|
+
structuredContent: { found: false }
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
const paths = await listVaultNotes(services.fs, detection.path);
|
|
616
|
+
const names = paths.map((p) => p.slice(detection.path?.length ?? 0).replace(/^\/+/, ""));
|
|
617
|
+
const source = services.obsidianVaultPath ? "CHAMBA_OBSIDIAN_VAULT_PATH" : "autodetected";
|
|
618
|
+
logger.info({ tool: TOOL_NAME13, vault: detection.path, notes: names.length }, "vault-status");
|
|
619
|
+
const shown = names.slice(0, MAX_LISTED);
|
|
620
|
+
const more = names.length > MAX_LISTED ? `
|
|
621
|
+
\u2026and ${names.length - MAX_LISTED} more` : "";
|
|
622
|
+
const text = `Vault: ${detection.path} (${source})
|
|
623
|
+
Notes chamba can see: ${names.length}
|
|
624
|
+
|
|
625
|
+
${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." : "");
|
|
626
|
+
return {
|
|
627
|
+
content: [{ type: "text", text }],
|
|
628
|
+
structuredContent: {
|
|
629
|
+
found: true,
|
|
630
|
+
vaultPath: detection.path,
|
|
631
|
+
source,
|
|
632
|
+
noteCount: names.length,
|
|
633
|
+
notes: shown
|
|
634
|
+
}
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
);
|
|
638
|
+
}
|
|
639
|
+
|
|
588
640
|
// src/tools/workspace-init.ts
|
|
589
641
|
import {
|
|
590
642
|
joinPath as joinPath4,
|
|
@@ -594,14 +646,14 @@ import {
|
|
|
594
646
|
WorkspaceScanner as WorkspaceScanner4
|
|
595
647
|
} from "@chamba/core";
|
|
596
648
|
import { z as z12 } from "zod";
|
|
597
|
-
var
|
|
598
|
-
var
|
|
649
|
+
var TOOL_NAME14 = "chamba_workspace_init";
|
|
650
|
+
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
651
|
function registerWorkspaceInit(server, logger, services) {
|
|
600
652
|
server.registerTool(
|
|
601
|
-
|
|
653
|
+
TOOL_NAME14,
|
|
602
654
|
{
|
|
603
655
|
title: "Init workspace",
|
|
604
|
-
description:
|
|
656
|
+
description: DESCRIPTION14,
|
|
605
657
|
inputSchema: {
|
|
606
658
|
root: z12.string().optional().describe("Workspace root to scan. Defaults to the directory chamba runs in.")
|
|
607
659
|
}
|
|
@@ -611,7 +663,7 @@ function registerWorkspaceInit(server, logger, services) {
|
|
|
611
663
|
const wsPath = joinPath4(workspaceRoot, WORKSPACE_RELATIVE_PATH);
|
|
612
664
|
if (await services.fs.exists(wsPath)) {
|
|
613
665
|
const currentContents = await services.fs.readFile(wsPath);
|
|
614
|
-
logger.info({ tool:
|
|
666
|
+
logger.info({ tool: TOOL_NAME14, wsPath }, "workspace.md already exists, not overwriting");
|
|
615
667
|
return {
|
|
616
668
|
content: [
|
|
617
669
|
{
|
|
@@ -631,7 +683,7 @@ ${currentContents}`
|
|
|
631
683
|
await services.fs.mkdir(joinPath4(workspaceRoot, WORKSPACE_DIR4));
|
|
632
684
|
await services.fs.writeFile(wsPath, markdown);
|
|
633
685
|
logger.info(
|
|
634
|
-
{ tool:
|
|
686
|
+
{ tool: TOOL_NAME14, wsPath, projects: workspace.projects.length },
|
|
635
687
|
"workspace.md created"
|
|
636
688
|
);
|
|
637
689
|
return {
|
|
@@ -657,20 +709,20 @@ import {
|
|
|
657
709
|
WORKSPACE_RELATIVE_PATH as WORKSPACE_RELATIVE_PATH2,
|
|
658
710
|
WorkspaceScanner as WorkspaceScanner5
|
|
659
711
|
} from "@chamba/core";
|
|
660
|
-
var
|
|
661
|
-
var
|
|
712
|
+
var TOOL_NAME15 = "chamba_workspace_reload";
|
|
713
|
+
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
714
|
function registerWorkspaceReload(server, logger, services) {
|
|
663
715
|
server.registerTool(
|
|
664
|
-
|
|
716
|
+
TOOL_NAME15,
|
|
665
717
|
{
|
|
666
718
|
title: "Reload workspace",
|
|
667
|
-
description:
|
|
719
|
+
description: DESCRIPTION15,
|
|
668
720
|
inputSchema: {}
|
|
669
721
|
},
|
|
670
722
|
async () => {
|
|
671
723
|
const wsPath = joinPath5(services.cwd, WORKSPACE_RELATIVE_PATH2);
|
|
672
724
|
if (!await services.fs.exists(wsPath)) {
|
|
673
|
-
logger.info({ tool:
|
|
725
|
+
logger.info({ tool: TOOL_NAME15, wsPath }, "no workspace.md to reload");
|
|
674
726
|
return {
|
|
675
727
|
content: [
|
|
676
728
|
{
|
|
@@ -684,7 +736,7 @@ function registerWorkspaceReload(server, logger, services) {
|
|
|
684
736
|
const scanner = new WorkspaceScanner5(services.fs);
|
|
685
737
|
const rescanned = renderWorkspaceMarkdown2(await scanner.scan(services.cwd));
|
|
686
738
|
if (textsEqual(current, rescanned)) {
|
|
687
|
-
logger.info({ tool:
|
|
739
|
+
logger.info({ tool: TOOL_NAME15, wsPath }, "workspace.md up to date");
|
|
688
740
|
return {
|
|
689
741
|
content: [
|
|
690
742
|
{
|
|
@@ -694,7 +746,7 @@ function registerWorkspaceReload(server, logger, services) {
|
|
|
694
746
|
]
|
|
695
747
|
};
|
|
696
748
|
}
|
|
697
|
-
logger.info({ tool:
|
|
749
|
+
logger.info({ tool: TOOL_NAME15, wsPath }, "workspace.md differs from re-scan");
|
|
698
750
|
return {
|
|
699
751
|
content: [
|
|
700
752
|
{
|
|
@@ -713,24 +765,24 @@ ${diffLines(current, rescanned)}
|
|
|
713
765
|
|
|
714
766
|
// src/tools/workspace-show.ts
|
|
715
767
|
import { joinPath as joinPath6, WORKSPACE_RELATIVE_PATH as WORKSPACE_RELATIVE_PATH3 } from "@chamba/core";
|
|
716
|
-
var
|
|
717
|
-
var
|
|
768
|
+
var TOOL_NAME16 = "chamba_workspace_show";
|
|
769
|
+
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
770
|
function registerWorkspaceShow(server, logger, services) {
|
|
719
771
|
server.registerTool(
|
|
720
|
-
|
|
772
|
+
TOOL_NAME16,
|
|
721
773
|
{
|
|
722
774
|
title: "Show workspace",
|
|
723
|
-
description:
|
|
775
|
+
description: DESCRIPTION16,
|
|
724
776
|
inputSchema: {}
|
|
725
777
|
},
|
|
726
778
|
async () => {
|
|
727
779
|
const path = joinPath6(services.cwd, WORKSPACE_RELATIVE_PATH3);
|
|
728
780
|
try {
|
|
729
781
|
const contents = await services.fs.readFile(path);
|
|
730
|
-
logger.info({ tool:
|
|
782
|
+
logger.info({ tool: TOOL_NAME16, path }, "workspace.md read");
|
|
731
783
|
return { content: [{ type: "text", text: contents }] };
|
|
732
784
|
} catch {
|
|
733
|
-
logger.info({ tool:
|
|
785
|
+
logger.info({ tool: TOOL_NAME16, path }, "no workspace.md found");
|
|
734
786
|
return {
|
|
735
787
|
content: [
|
|
736
788
|
{
|
|
@@ -754,6 +806,7 @@ function createServer(logger, services = createNodeServices()) {
|
|
|
754
806
|
registerWorkspaceReload(server, logger, services);
|
|
755
807
|
registerLoadContext(server, logger, services);
|
|
756
808
|
registerSummarizeToVault(server, logger, services);
|
|
809
|
+
registerVaultStatus(server, logger, services);
|
|
757
810
|
registerGeneratePlan(server, logger, services);
|
|
758
811
|
registerReviewPlan(server, logger, services);
|
|
759
812
|
registerCreateWorktree(server, logger, services);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chamba/mcp",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
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.3.
|
|
40
|
-
"@chamba/core": "0.3.
|
|
39
|
+
"@chamba/adapters": "0.3.2",
|
|
40
|
+
"@chamba/core": "0.3.2"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/node": "^22.0.0",
|