things-mcp 0.1.1 → 0.1.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.
- checksums.yaml +4 -4
- data/bin/test_connection +2 -2
- data/bin/things_mcp_server +3 -2
- data/lib/things_mcp/database.rb +28 -4
- data/lib/things_mcp/handlers.rb +3 -3
- data/lib/things_mcp/server.rb +14 -11
- data/lib/things_mcp/version.rb +1 -1
- data/lib/things_mcp.rb +6 -6
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 66584b39e6d5286abeb4a75f08f029bab5c7c1b7b7f42129ee12986086fa7927
|
4
|
+
data.tar.gz: bb7603686e15d0dc366f746e263dbb99cebb00ce35377e8ae49fb7f468658dc0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ff846805290fb8e7e628b8809855c2538852be5f0ea69766d176fa6065081ae93af010b2958c68bdc4ce5014f580375939701bf7964a1d915ea3d72d0d5f30e
|
7
|
+
data.tar.gz: 8450f45b5c44b9cf8a37762e48cb7c4fe2b64a6e409ebcd2603036726c49535ad862b9ded6796dc13788694562c10e1406ec7547c7364c1bfa1d91b61312b8e9
|
data/bin/test_connection
CHANGED
data/bin/things_mcp_server
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
lib = File.expand_path("../lib", __dir__)
|
5
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
6
|
+
require "things_mcp/server"
|
6
7
|
|
7
8
|
# Run the MCP server
|
8
9
|
ThingsMcp::Server.new.run
|
data/lib/things_mcp/database.rb
CHANGED
@@ -303,7 +303,18 @@ module ThingsMcp
|
|
303
303
|
private
|
304
304
|
|
305
305
|
def find_database_path
|
306
|
-
|
306
|
+
# Use actual user's home directory, not the process owner's
|
307
|
+
actual_home = ENV["HOME"] || Dir.home
|
308
|
+
# If running as root, try to find the real user's home directory
|
309
|
+
if actual_home == "/var/root" && ENV["SUDO_USER"]
|
310
|
+
actual_home = "/Users/#{ENV["SUDO_USER"]}"
|
311
|
+
elsif actual_home == "/var/root"
|
312
|
+
# Fallback: look for the most recent user directory
|
313
|
+
user_dirs = Dir.glob("/Users/*").select { |d| File.directory?(d) && !File.basename(d).start_with?(".") }
|
314
|
+
actual_home = user_dirs.max_by { |d| File.mtime(d) } if user_dirs.any?
|
315
|
+
end
|
316
|
+
|
317
|
+
group_containers_dir = "#{actual_home}/Library/Group Containers"
|
307
318
|
|
308
319
|
# Find Things-specific directories to avoid permission issues
|
309
320
|
things_dirs = Dir.glob("#{group_containers_dir}/*").select do |dir|
|
@@ -311,11 +322,24 @@ module ThingsMcp
|
|
311
322
|
end
|
312
323
|
|
313
324
|
things_dirs.each do |things_dir|
|
314
|
-
|
315
|
-
|
325
|
+
# First try to find the current database (not in Backups folder)
|
326
|
+
current_pattern = "#{things_dir}/*/Things Database.thingsdatabase/main.sqlite"
|
327
|
+
current_matches = Dir.glob(current_pattern).reject { |path| path.include?("/Backups/") }
|
328
|
+
|
329
|
+
unless current_matches.empty?
|
330
|
+
return current_matches.first
|
331
|
+
end
|
316
332
|
|
317
|
-
|
333
|
+
# Fallback: look for any main.sqlite but exclude backups
|
334
|
+
fallback_pattern = "#{things_dir}/*/*/main.sqlite"
|
335
|
+
fallback_matches = Dir.glob(fallback_pattern).reject { |path| path.include?("/Backups/") }
|
336
|
+
|
337
|
+
unless fallback_matches.empty?
|
338
|
+
return fallback_matches.first
|
339
|
+
end
|
318
340
|
end
|
341
|
+
|
342
|
+
nil
|
319
343
|
end
|
320
344
|
|
321
345
|
def todo_columns
|
data/lib/things_mcp/handlers.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "json"
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
require "things_mcp/database"
|
5
|
+
require "things_mcp/url_scheme"
|
6
|
+
require "things_mcp/formatters"
|
7
7
|
|
8
8
|
module ThingsMcp
|
9
9
|
# Tool call handlers for MCP server
|
data/lib/things_mcp/server.rb
CHANGED
@@ -3,10 +3,10 @@
|
|
3
3
|
require "mcp"
|
4
4
|
require "mcp/transports/stdio"
|
5
5
|
require "logger"
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
require "things_mcp/tools"
|
7
|
+
require "things_mcp/handlers"
|
8
|
+
require "things_mcp/database"
|
9
|
+
require "things_mcp/url_scheme"
|
10
10
|
|
11
11
|
module ThingsMcp
|
12
12
|
# MCP server implementation for Things 3 integration
|
@@ -95,7 +95,7 @@ module ThingsMcp
|
|
95
95
|
required: tool_def[:inputSchema][:required],
|
96
96
|
)
|
97
97
|
|
98
|
-
define_singleton_method(:call) do |
|
98
|
+
define_singleton_method(:call) do |server_context:, **arguments|
|
99
99
|
# Convert symbol keys to string keys for consistent access
|
100
100
|
string_arguments = arguments.transform_keys(&:to_s)
|
101
101
|
result = ThingsMcp::Handlers.handle_tool_call(name, string_arguments)
|
@@ -107,12 +107,15 @@ module ThingsMcp
|
|
107
107
|
},
|
108
108
|
])
|
109
109
|
rescue => e
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
110
|
+
# Log the full error to stderr for debugging
|
111
|
+
$stderr.puts "ERROR in tool #{name}: #{e.class}: #{e.message}"
|
112
|
+
$stderr.puts "Arguments: #{string_arguments.inspect}"
|
113
|
+
$stderr.puts "Backtrace:"
|
114
|
+
e.backtrace.each { |line| $stderr.puts " #{line}" }
|
115
|
+
$stderr.flush
|
116
|
+
|
117
|
+
# Also raise the error so MCP can handle it properly
|
118
|
+
raise e
|
116
119
|
end
|
117
120
|
end
|
118
121
|
end
|
data/lib/things_mcp/version.rb
CHANGED
data/lib/things_mcp.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "mcp"
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
require "things_mcp/server"
|
5
|
+
require "things_mcp/database"
|
6
|
+
require "things_mcp/handlers"
|
7
|
+
require "things_mcp/tools"
|
8
|
+
require "things_mcp/url_scheme"
|
9
|
+
require "things_mcp/formatters"
|
10
10
|
|
11
11
|
# ThingsMcp provides a Model Context Protocol (MCP) server for Things 3
|
12
12
|
#
|