@@ -58,25 +58,56 @@ fn find_mcp_binary(app: &AppHandle) -> Option<std::path::PathBuf> {
5858 None
5959}
6060
61- #[ tauri:: command]
62- pub fn setup_claude_mcp ( app : AppHandle ) -> Result < ( ) , String > {
63- let binary = find_mcp_binary ( & app) . ok_or_else ( || {
64- "Cannot find timesheeps-mcp binary. Build the project first with `pnpm tauri dev` or `pnpm tauri build`." . to_string ( )
65- } ) ?;
61+ /// Returns all candidate Claude Desktop config paths that exist on this machine.
62+ /// Covers both the traditional install (%APPDATA%\Claude) and the Microsoft
63+ /// Store sandboxed install (%LOCALAPPDATA%\Packages\Claude_*\LocalCache\Roaming\Claude).
64+ /// If neither directory exists yet, falls back to the traditional path (creates it).
65+ fn find_claude_config_dirs ( ) -> Vec < std:: path:: PathBuf > {
66+ let mut dirs: Vec < std:: path:: PathBuf > = Vec :: new ( ) ;
67+
68+ // Traditional install
69+ if let Ok ( appdata) = std:: env:: var ( "APPDATA" ) {
70+ let p = std:: path:: PathBuf :: from ( appdata) . join ( "Claude" ) ;
71+ if p. exists ( ) {
72+ dirs. push ( p) ;
73+ }
74+ }
6675
67- let binary_path = binary. to_string_lossy ( ) . to_string ( ) ;
76+ // Store install: %LOCALAPPDATA%\Packages\Claude_<publisher-id>\LocalCache\Roaming\Claude
77+ if let Ok ( localappdata) = std:: env:: var ( "LOCALAPPDATA" ) {
78+ let packages = std:: path:: PathBuf :: from ( localappdata) . join ( "Packages" ) ;
79+ if let Ok ( entries) = std:: fs:: read_dir ( & packages) {
80+ for entry in entries. flatten ( ) {
81+ let name = entry. file_name ( ) ;
82+ let name_str = name. to_string_lossy ( ) ;
83+ if name_str. starts_with ( "Claude_" ) {
84+ let p = entry. path ( ) . join ( "LocalCache" ) . join ( "Roaming" ) . join ( "Claude" ) ;
85+ if p. exists ( ) {
86+ dirs. push ( p) ;
87+ }
88+ }
89+ }
90+ }
91+ }
6892
69- // Read existing Claude Desktop config or start fresh
70- let appdata = std:: env:: var ( "APPDATA" )
71- . map_err ( |_| "APPDATA environment variable not set" . to_string ( ) ) ?;
72- let claude_dir = std:: path:: Path :: new ( & appdata) . join ( "Claude" ) ;
73- std:: fs:: create_dir_all ( & claude_dir)
74- . map_err ( |e| format ! ( "Cannot create Claude config dir: {}" , e) ) ?;
93+ // Fallback: create the traditional path if nothing was found
94+ if dirs. is_empty ( ) {
95+ if let Ok ( appdata) = std:: env:: var ( "APPDATA" ) {
96+ dirs. push ( std:: path:: PathBuf :: from ( appdata) . join ( "Claude" ) ) ;
97+ }
98+ }
99+
100+ dirs
101+ }
75102
76- let config_path = claude_dir. join ( "claude_desktop_config.json" ) ;
103+ fn write_claude_config ( dir : & std:: path:: Path , binary_path : & str ) -> Result < ( ) , String > {
104+ std:: fs:: create_dir_all ( dir)
105+ . map_err ( |e| format ! ( "Cannot create {}: {}" , dir. display( ) , e) ) ?;
106+
107+ let config_path = dir. join ( "claude_desktop_config.json" ) ;
77108 let mut config: serde_json:: Value = if config_path. exists ( ) {
78109 let content = std:: fs:: read_to_string ( & config_path)
79- . map_err ( |e| format ! ( "Cannot read existing config : {}" , e) ) ?;
110+ . map_err ( |e| format ! ( "Cannot read {} : {}" , config_path . display ( ) , e) ) ?;
80111 serde_json:: from_str ( & content) . unwrap_or ( serde_json:: json!( { } ) )
81112 } else {
82113 serde_json:: json!( { } )
@@ -85,15 +116,28 @@ pub fn setup_claude_mcp(app: AppHandle) -> Result<(), String> {
85116 if config. get ( "mcpServers" ) . is_none ( ) {
86117 config[ "mcpServers" ] = serde_json:: json!( { } ) ;
87118 }
88-
89- config[ "mcpServers" ] [ "timesheeps" ] = serde_json:: json!( {
90- "command" : binary_path
91- } ) ;
119+ config[ "mcpServers" ] [ "timesheeps" ] = serde_json:: json!( { "command" : binary_path } ) ;
92120
93121 let json = serde_json:: to_string_pretty ( & config)
94122 . map_err ( |e| format ! ( "Cannot serialize config: {}" , e) ) ?;
95123 std:: fs:: write ( & config_path, json)
96- . map_err ( |e| format ! ( "Cannot write Claude config: {}" , e) ) ?;
124+ . map_err ( |e| format ! ( "Cannot write {}: {}" , config_path. display( ) , e) ) ?;
125+
126+ Ok ( ( ) )
127+ }
128+
129+ #[ tauri:: command]
130+ pub fn setup_claude_mcp ( app : AppHandle ) -> Result < ( ) , String > {
131+ let binary = find_mcp_binary ( & app) . ok_or_else ( || {
132+ "Cannot find timesheeps-mcp binary. Build the project first with `pnpm tauri dev` or `pnpm tauri build`." . to_string ( )
133+ } ) ?;
134+
135+ let binary_path = binary. to_string_lossy ( ) . to_string ( ) ;
136+
137+ let dirs = find_claude_config_dirs ( ) ;
138+ for dir in & dirs {
139+ write_claude_config ( dir, & binary_path) ?;
140+ }
97141
98142 Ok ( ( ) )
99143}
0 commit comments