git-fit 0.22.0 → 0.23.0
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/lib/git-fit.rb +2 -0
- data/lib/git_fit/cli/mcp.rb +24 -0
- data/lib/git_fit/cli.rb +3 -0
- data/lib/git_fit/mcp/tools.rb +118 -0
- data/lib/git_fit/mcp.rb +19 -0
- data/lib/git_fit/version.rb +1 -1
- metadata +18 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 05e915997e2a8843c5a47a964ff957134529c0712a2dd0743bd9f71828c87d3d
|
|
4
|
+
data.tar.gz: 96307ebf14dd9c1a37fa8615552d0daccc34218d6c2ff99ec6bfaad0621e5954
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4b2e303432bab61591e5cc2835f3978574b21357f71bad88c37801c90614bc6f19f0f809cf7136c02b0d6e45d391aa6a76a1caeedd7666b2b69f5894d41f553f
|
|
7
|
+
data.tar.gz: 37090a85b6374f2ce0ee85b51c89b0bfc2ff6fbbf6d2a26c217ef4a16649480f78205b2d5abed165d3307763c464baae3c5d1f6e7144fc86aeb2a0c186e7751a
|
data/lib/git-fit.rb
CHANGED
|
@@ -90,7 +90,9 @@ require_relative 'git_fit/install/actions'
|
|
|
90
90
|
require_relative 'git_fit/cli/install_cli'
|
|
91
91
|
require_relative 'git_fit/cli/purge_cli'
|
|
92
92
|
require_relative 'git_fit/cli/gh_cli'
|
|
93
|
+
require_relative 'git_fit/mcp'
|
|
93
94
|
require_relative 'git_fit/cli/export'
|
|
95
|
+
require_relative 'git_fit/cli/mcp'
|
|
94
96
|
require_relative 'git_fit/cli/import_cli'
|
|
95
97
|
require_relative 'git_fit/cli/geo_cli'
|
|
96
98
|
require_relative 'git_fit/strava_web/file_check'
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'mcp'
|
|
4
|
+
|
|
5
|
+
module GitFit
|
|
6
|
+
class McpCLI < Thor
|
|
7
|
+
desc 'serve', 'Start the MCP stdio server (read-only workouts data for AI clients)'
|
|
8
|
+
|
|
9
|
+
no_commands do
|
|
10
|
+
def git_fit_config
|
|
11
|
+
@git_fit_config ||= GitFit::Config.new(options[:config])
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def serve
|
|
16
|
+
config = git_fit_config
|
|
17
|
+
server = GitFit::MCP.build_server(config)
|
|
18
|
+
::MCP::Server::Transports::StdioTransport.new(server).open
|
|
19
|
+
rescue StandardError => e
|
|
20
|
+
say_status :error, "MCP server failed: #{e.message}", :red
|
|
21
|
+
exit 1
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
data/lib/git_fit/cli.rb
CHANGED
|
@@ -23,6 +23,9 @@ module GitFit
|
|
|
23
23
|
desc 'export SUBCOMMAND', 'Export activities to various formats'
|
|
24
24
|
subcommand 'export', ExportCLI
|
|
25
25
|
|
|
26
|
+
desc 'mcp serve', 'Start the MCP stdio server (read-only workouts data for AI clients)'
|
|
27
|
+
subcommand 'mcp', McpCLI
|
|
28
|
+
|
|
26
29
|
desc 'version', 'Show version'
|
|
27
30
|
def version
|
|
28
31
|
puts "git-fit v#{GitFit::VERSION}"
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
require 'sequel'
|
|
5
|
+
require 'mcp'
|
|
6
|
+
|
|
7
|
+
module GitFit
|
|
8
|
+
module MCP
|
|
9
|
+
# 只读 MCP tools —— expose 本地 workouts DB 给 AI 客户端(Claude/Code/opencode 等)。
|
|
10
|
+
# 数据已公开(Pages 站点),无隐私增量;SQLite readonly 打开。
|
|
11
|
+
#
|
|
12
|
+
# 输出格式约定:query_activities 使用与 insights 摘要一致的紧凑行
|
|
13
|
+
# (run_id | 日期 类型 距离 时长 HR 爬升),供 get_activity 下钻。
|
|
14
|
+
module Tools
|
|
15
|
+
ACTIVITY_COLUMNS = %i[
|
|
16
|
+
run_id name distance moving_time elapsed_time sport_category sport_type
|
|
17
|
+
start_date start_date_local location_country summary_polyline
|
|
18
|
+
average_heartrate max_heartrate average_cadence max_cadence
|
|
19
|
+
average_power max_power average_temperature calories average_speed
|
|
20
|
+
elevation_gain elevation_loss elevation_min elevation_max steps source
|
|
21
|
+
].freeze
|
|
22
|
+
|
|
23
|
+
module_function
|
|
24
|
+
|
|
25
|
+
def db(config)
|
|
26
|
+
Sequel.sqlite(config.db_path, readonly: true)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def activity_line(row)
|
|
30
|
+
parts = [row[:run_id].to_s, row[:start_date_local].to_s[0, 10], row[:sport_category].to_s]
|
|
31
|
+
parts << format('%.1fkm', row[:distance] / 1000.0) if row[:distance]
|
|
32
|
+
parts << "#{(row[:moving_time] / 60).round}min" if row[:moving_time]
|
|
33
|
+
parts << "HR#{row[:average_heartrate].round}" if row[:average_heartrate]
|
|
34
|
+
parts << "asc#{row[:elevation_gain].round}m" if row[:elevation_gain]
|
|
35
|
+
parts.join(' | ')
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
class QueryActivitiesTool < ::MCP::Tool
|
|
40
|
+
tool_name 'query_activities'
|
|
41
|
+
description '查询运动活动列表(按日期范围/运动类型过滤,返回最近的紧凑摘要行)。' \
|
|
42
|
+
'行格式:run_id | 日期 | 类型 | 距离 | 时长 | HR | 爬升。'
|
|
43
|
+
|
|
44
|
+
input_schema(
|
|
45
|
+
properties: {
|
|
46
|
+
from_date: { type: 'string', description: '起始日期 YYYY-MM-DD(含)', pattern: '^\\d{4}-\\d{2}-\\d{2}$' },
|
|
47
|
+
to_date: { type: 'string', description: '结束日期 YYYY-MM-DD(含)', pattern: '^\\d{4}-\\d{2}-\\d{2}$' },
|
|
48
|
+
sport: { type: 'string', description: '运动类型(ride/run/hike/walk/swim/workout/other)' },
|
|
49
|
+
limit: { type: 'integer', description: '返回条数上限(1-500)', default: 50 },
|
|
50
|
+
},
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
class << self
|
|
54
|
+
def call(server_context:, from_date: nil, to_date: nil, sport: nil, limit: 50)
|
|
55
|
+
db = GitFit::MCP::Tools.db(server_context[:config])
|
|
56
|
+
rows = db[:activities].order(Sequel.desc(:start_date_local)).limit(2000).all
|
|
57
|
+
rows = rows.select { |r| r[:start_date_local].to_s[0, 10] >= from_date } if from_date
|
|
58
|
+
rows = rows.select { |r| r[:start_date_local].to_s[0, 10] <= to_date } if to_date
|
|
59
|
+
rows = rows.select { |r| r[:sport_category] == sport } if sport && sport != 'all'
|
|
60
|
+
rows = rows.first(limit.to_i.clamp(1, 500))
|
|
61
|
+
lines = rows.map { |r| GitFit::MCP::Tools.activity_line(r) }
|
|
62
|
+
body = lines.empty? ? '无匹配活动' : "#{rows.size} 条匹配:\n#{lines.join("\n")}"
|
|
63
|
+
::MCP::Tool::Response.new([{ type: 'text', text: body }])
|
|
64
|
+
ensure
|
|
65
|
+
db&.disconnect
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
class GetActivityTool < ::MCP::Tool
|
|
71
|
+
tool_name 'get_activity'
|
|
72
|
+
description '按 run_id 获取单个活动的全字段详情。run_id 来自 query_activities。'
|
|
73
|
+
|
|
74
|
+
input_schema(
|
|
75
|
+
properties: {
|
|
76
|
+
run_id: { type: 'string', description: '活动 ID(如 garmin_cn_12345678)' },
|
|
77
|
+
},
|
|
78
|
+
required: ['run_id'],
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
class << self
|
|
82
|
+
def call(run_id:, server_context:)
|
|
83
|
+
db = GitFit::MCP::Tools.db(server_context[:config])
|
|
84
|
+
row = db[:activities].first(run_id: run_id)
|
|
85
|
+
unless row
|
|
86
|
+
return ::MCP::Tool::Response.new(
|
|
87
|
+
[{ type: 'text', text: "活动不存在:#{run_id}\n Fix: 先用 query_activities 查询可用 run_id" }],
|
|
88
|
+
error: true,
|
|
89
|
+
)
|
|
90
|
+
end
|
|
91
|
+
::MCP::Tool::Response.new([{ type: 'text', text: JSON.pretty_generate(
|
|
92
|
+
GitFit::MCP::Tools::ACTIVITY_COLUMNS.to_h { |k| [k, row[k]] },
|
|
93
|
+
) }])
|
|
94
|
+
ensure
|
|
95
|
+
db&.disconnect
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
class GetStatsTool < ::MCP::Tool
|
|
101
|
+
tool_name 'get_stats'
|
|
102
|
+
description '获取全量统计摘要:summary(全历史累计)/ monthly(按月)/ yearly(按年)/ streaks(连续天数)/ activity_types。' \
|
|
103
|
+
'注意 summary 是全历史累计,当期对比请看 monthly/yearly 分组行。'
|
|
104
|
+
|
|
105
|
+
input_schema(properties: {})
|
|
106
|
+
|
|
107
|
+
class << self
|
|
108
|
+
def call(server_context:)
|
|
109
|
+
db = GitFit::MCP::Tools.db(server_context[:config])
|
|
110
|
+
stats = GitFit::Export::Calculator.new(db: db).call
|
|
111
|
+
::MCP::Tool::Response.new([{ type: 'text', text: JSON.pretty_generate(stats) }])
|
|
112
|
+
ensure
|
|
113
|
+
db&.disconnect
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
data/lib/git_fit/mcp.rb
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'mcp/tools'
|
|
4
|
+
|
|
5
|
+
module GitFit
|
|
6
|
+
module MCP
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
# 构建 MCP server(stdio transport 由 CLI 层启动)。
|
|
10
|
+
def build_server(config)
|
|
11
|
+
::MCP::Server.new(
|
|
12
|
+
name: 'git-fit-workouts',
|
|
13
|
+
version: GitFit::VERSION,
|
|
14
|
+
tools: [QueryActivitiesTool, GetActivityTool, GetStatsTool],
|
|
15
|
+
server_context: { config: config },
|
|
16
|
+
)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
data/lib/git_fit/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: git-fit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.23.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Lax
|
|
@@ -247,6 +247,20 @@ dependencies:
|
|
|
247
247
|
- - "~>"
|
|
248
248
|
- !ruby/object:Gem::Version
|
|
249
249
|
version: '1.0'
|
|
250
|
+
- !ruby/object:Gem::Dependency
|
|
251
|
+
name: mcp
|
|
252
|
+
requirement: !ruby/object:Gem::Requirement
|
|
253
|
+
requirements:
|
|
254
|
+
- - "~>"
|
|
255
|
+
- !ruby/object:Gem::Version
|
|
256
|
+
version: '1.4'
|
|
257
|
+
type: :runtime
|
|
258
|
+
prerelease: false
|
|
259
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
260
|
+
requirements:
|
|
261
|
+
- - "~>"
|
|
262
|
+
- !ruby/object:Gem::Version
|
|
263
|
+
version: '1.4'
|
|
250
264
|
description: A git extension CLI for aggregating, managing, and exporting fitness
|
|
251
265
|
activity data from multiple sources (Garmin, Strava, Keep, etc.)
|
|
252
266
|
email:
|
|
@@ -275,6 +289,7 @@ files:
|
|
|
275
289
|
- lib/git_fit/cli/gh_cli.rb
|
|
276
290
|
- lib/git_fit/cli/import_cli.rb
|
|
277
291
|
- lib/git_fit/cli/install_cli.rb
|
|
292
|
+
- lib/git_fit/cli/mcp.rb
|
|
278
293
|
- lib/git_fit/cli/purge_cli.rb
|
|
279
294
|
- lib/git_fit/cli/strava.rb
|
|
280
295
|
- lib/git_fit/cli/sync.rb
|
|
@@ -332,6 +347,8 @@ files:
|
|
|
332
347
|
- lib/git_fit/llm/errors.rb
|
|
333
348
|
- lib/git_fit/llm/prompts.rb
|
|
334
349
|
- lib/git_fit/llm/template.rb
|
|
350
|
+
- lib/git_fit/mcp.rb
|
|
351
|
+
- lib/git_fit/mcp/tools.rb
|
|
335
352
|
- lib/git_fit/parser.rb
|
|
336
353
|
- lib/git_fit/parser/base.rb
|
|
337
354
|
- lib/git_fit/parser/fit.rb
|