Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions hosts/glyph/services/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@
age.secrets.obsidian-auth-token = {
file = ./../secrets/obsidian-auth-token.age;
mode = "400";
owner = "mu";
group = "users";
owner = "obsidian";
group = "obsidian";
};

rc.obsidian-sync = {
Expand Down Expand Up @@ -133,6 +133,10 @@
enable = true;
authTokenFile = config.age.secrets.graphite-auth-token.path;
};
services.obsidian-vault-mcp = {
enable = true;
inherit (config.rc.obsidian-sync) vaultPath;
};
services.mcpjungle = {
enable = true;
servers.basic-memory = {
Expand All @@ -155,6 +159,10 @@
url = "http://127.0.0.1:8094/mcp";
description = "Graphite CLI for stacked PRs and code review";
};
servers.obsidian-vault = {
url = "http://127.0.0.1:8097/mcp";
description = "Read and write files in the Obsidian vault";
};
servers.context7 = {
url = "https://mcp.context7.com/mcp";
description = "Up-to-date library documentation and code examples";
Expand Down
1 change: 1 addition & 0 deletions modules/nixos/llm/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
./kagi.nix
./mcp-nixos.nix
./mcpjungle.nix
./obsidian-vault-mcp.nix
];
}
73 changes: 73 additions & 0 deletions modules/nixos/llm/obsidian-vault-mcp.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
{
config,
pkgs,
lib,
...
}: let
cfg = config.services.obsidian-vault-mcp;

startScript = pkgs.writeShellScript "obsidian-vault-mcp-start" ''
exec ${lib.getExe pkgs.mcp-proxy} \
--host ${cfg.host} \
--port ${toString cfg.port} \
--transport streamablehttp \
-- ${lib.getExe pkgs.mcp-server-filesystem} ${lib.escapeShellArg cfg.vaultPath}
'';
in {
options.services.obsidian-vault-mcp = {
enable = lib.mkEnableOption "Obsidian vault filesystem MCP server (stdio→HTTP bridge)";

port = lib.mkOption {
type = lib.types.port;
default = 8097;
description = "Port for the streamable HTTP transport.";
};

host = lib.mkOption {
type = lib.types.str;
default = "127.0.0.1";
description = "Address to bind the HTTP server to.";
};

vaultPath = lib.mkOption {
type = lib.types.str;
description = "Absolute path to the Obsidian vault directory.";
};

openFirewall = lib.mkEnableOption "opening firewall port for obsidian-vault-mcp";
};

config = lib.mkIf cfg.enable {
systemd.services.obsidian-vault-mcp = {
description = "Obsidian Vault Filesystem MCP Server";
after = ["network-online.target"];
wants = ["network-online.target"];
wantedBy = ["multi-user.target"];

serviceConfig = {
ExecStart = "${startScript}";
# Runs as the shared obsidian user so it has full read/write access
# to vault files created by obsidian-sync.
User = "obsidian";
Group = "obsidian";
WorkingDirectory = "/var/lib/obsidian";
Restart = "on-failure";
RestartSec = 5;

# Hardening
NoNewPrivileges = true;
PrivateDevices = true;
PrivateTmp = true;
ProtectHome = true;
ProtectSystem = "strict";
ReadWritePaths = [cfg.vaultPath "/var/lib/obsidian"];
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectControlGroups = true;
RestrictSUIDSGID = true;
};
};

networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [cfg.port];
};
}
25 changes: 16 additions & 9 deletions modules/nixos/obsidian-sync.nix
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,17 @@
config,
lib,
pkgs,
username,
...
}: let
cfg = config.rc.obsidian-sync;
homeDir = config.users.users.${username}.home;
stateDir = "/var/lib/obsidian";
in {
options.rc.obsidian-sync = {
enable = lib.mkEnableOption "Obsidian headless vault sync";

vaultPath = lib.mkOption {
type = lib.types.str;
default = "${homeDir}/vault";
default = "${stateDir}/vault";
description = "Local path to the vault directory.";
};

Expand All @@ -24,9 +23,16 @@ in {
};

config = lib.mkIf cfg.enable {
users.users.obsidian = {
isSystemUser = true;
group = "obsidian";
home = stateDir;
};
users.groups.obsidian = {};

systemd.tmpfiles.rules = [
"d ${cfg.vaultPath} 0755 ${username} users -"
"d ${homeDir}/.config/obsidian-headless 0700 ${username} users -"
"d ${cfg.vaultPath} 0755 obsidian obsidian -"
"d ${stateDir}/.config/obsidian-headless 0700 obsidian obsidian -"
];

systemd.services.obsidian-sync = {
Expand All @@ -36,9 +42,10 @@ in {
wants = ["network-online.target"];

serviceConfig = {
User = username;
Group = "users";
WorkingDirectory = homeDir;
User = "obsidian";
Group = "obsidian";
WorkingDirectory = stateDir;
StateDirectory = "obsidian";

EnvironmentFile = cfg.authTokenFile;

Expand All @@ -53,7 +60,7 @@ in {
NoNewPrivileges = true;
PrivateTmp = true;
ProtectSystem = "strict";
ReadWritePaths = [cfg.vaultPath "${homeDir}/.config/obsidian-headless"];
ReadWritePaths = [cfg.vaultPath "${stateDir}/.config/obsidian-headless"];
};
};
};
Expand Down
Loading