feat(mcp): serve safe source file assets

Add a stdio MCP server for searching and reading safe engineering source files from the wiki file asset index.

The implementation uses registry-backed ACL checks, engineering-file whitelisting, asset:// resource URIs, read-only SQLite access, CLI entrypoints, optional MCP packaging, and unittest coverage for search, metadata, resource reads, blocked sources, bot ACLs, and size limits.

Validation: python3 -m unittest discover -v; python3 -m py_compile obsidian_wiki/config.py obsidian_wiki/file_assets.py obsidian_wiki/mcp_assets.py obsidian_wiki/mcp_server.py obsidian_wiki/cli.py tests/test_mcp_assets.py; real BJD vault search/read smoke tests.
This commit is contained in:
nac
2026-07-05 11:10:41 +00:00
parent 777607dc29
commit 76a480a0b7
10 changed files with 896 additions and 2 deletions
+25
View File
@@ -453,6 +453,7 @@ def cmd_file_index_search(args: argparse.Namespace) -> int:
competitor=args.competitor,
status=args.status,
include_staged=not args.active_only,
read_only=True,
)
if args.json:
print(json.dumps(rows, ensure_ascii=False, indent=2))
@@ -479,6 +480,23 @@ def cmd_file_index_stage(args: argparse.Namespace) -> int:
return 0
def cmd_mcp_server(args: argparse.Namespace) -> int:
from obsidian_wiki.mcp_server import main as mcp_main
argv: list[str] = []
if args.vault:
argv.extend(["--vault", args.vault])
if args.db:
argv.extend(["--db", args.db])
if args.profile:
argv.extend(["--profile", args.profile])
if args.max_file_bytes is not None:
argv.extend(["--max-file-bytes", str(args.max_file_bytes)])
if args.expose_paths:
argv.append("--expose-paths")
return mcp_main(argv)
def cmd_bot_view_list(args: argparse.Namespace) -> int:
vault_path = _require_vault(args)
for name in list_profiles(vault_path):
@@ -570,6 +588,13 @@ def build_parser() -> argparse.ArgumentParser:
ftp.add_argument("--visibility", default="internal", help="initial visibility")
ftp.set_defaults(func=cmd_file_index_stage)
mp = sub.add_parser("mcp-server", help="run the stdio MCP server for safe source-file lookup")
_add_file_index_storage_args(mp)
mp.add_argument("--profile", help="bot profile name for ACL checks")
mp.add_argument("--max-file-bytes", type=int, help="maximum resource size, 0 disables the limit")
mp.add_argument("--expose-paths", action="store_true", help="include archive/absolute paths in tool output")
mp.set_defaults(func=cmd_mcp_server)
bp = sub.add_parser("bot-view", help="derive isolated chatbot views from the mother vault")
bot_sub = bp.add_subparsers(dest="bot_view_command")