linear-toon-mcp 0.5.1 → 0.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bf06d4bccdbce8b42b754913248e6d2380aa8f695725714de733603a8fd65e6b
4
- data.tar.gz: 32e7d3447fc0a55462f6f8b544bbe27801a4ac22d8192ec76208d99236275d73
3
+ metadata.gz: 3c8a4dfd15f2122d8742273f0a2b305d9f52f15b26173f177589348efcaceffb
4
+ data.tar.gz: 5f6f12e5bb56fe7c62cdabf552e110bd6b91dfabe0d0a6c241de074c5d1a02b3
5
5
  SHA512:
6
- metadata.gz: 2aa03787fd5668f525d274650f8c334caf9e0c199d1c0ab93f96c6d609f4ee92f89d412af4daa9a3a1052e50fa30c813624e4c5e3ae10ffedc55616965977591
7
- data.tar.gz: 255d287d3d61419cb4dcecbb224ef4b840dc821aa6fb09cd4109803018d30cf8e15f4300ee7c1fca82db8235b305cd193cda78fe8a420fcb36c14cb19419a2a0
6
+ metadata.gz: b163ae42837c5ae08eecf3b3897345f8c81312b7692a937ad0ef9586a42978155e2e1260fe7aeaa91d5fde1dddf29f0d0c5b8bad40658351dc925c017e4507ad
7
+ data.tar.gz: abd70a25debba62a651736fc0bfc018bda3171b3dc71070a2a4c17e5f2bd3476519def4f80dfb4c51853ad513ef9ecf898fc40aa3ad5630415144a9dd7e4e4a9
data/README.md CHANGED
@@ -56,6 +56,7 @@ claude mcp add linear-toon -e LINEAR_API_KEY=lin_api_xxxxx -- linear-toon-mcp
56
56
  | `create_issue` | Create a new Linear issue. Accepts human-friendly names for team, assignee, state, labels, project, cycle, and milestone (resolved to IDs automatically). Supports issue relations and link attachments. |
57
57
  | `update_issue` | Update an existing Linear issue by ID. Supports partial updates, null to remove fields, and relation replacement. |
58
58
  | `create_comment` | Create a comment on a Linear issue. Supports Markdown content and threaded replies via parentId. |
59
+ | `list_comments` | List comments for a specific Linear issue in chronological order. Returns each comment's id, body, author, and timestamps. |
59
60
 
60
61
  ## Development
61
62
 
@@ -92,10 +92,10 @@ module LinearToonMcp
92
92
  raise Error, "Issue creation failed" unless result["success"]
93
93
 
94
94
  issue = result["issue"]
95
- create_relations(client, issue["id"], **kwargs)
96
- create_links(client, issue["id"], kwargs[:links])
95
+ warnings = post_create(client, issue["id"], **kwargs)
97
96
 
98
97
  text = Toon.encode(issue)
98
+ text += "\nWARNING (issue was created): #{warnings.join("; ")}" if warnings.any?
99
99
  MCP::Tool::Response.new([{type: "text", text:}])
100
100
  rescue Error => e
101
101
  MCP::Tool::Response.new([{type: "text", text: e.message}], error: true)
@@ -103,6 +103,21 @@ module LinearToonMcp
103
103
 
104
104
  private
105
105
 
106
+ def post_create(client, issue_id, links: nil, **kwargs)
107
+ warnings = []
108
+ begin
109
+ create_relations(client, issue_id, **kwargs)
110
+ rescue Error => e
111
+ warnings << e.message
112
+ end
113
+ begin
114
+ create_links(client, issue_id, links)
115
+ rescue Error => e
116
+ warnings << e.message
117
+ end
118
+ warnings
119
+ end
120
+
106
121
  def add_direct_fields(input, description: nil, priority: nil, estimate: nil,
107
122
  dueDate: nil, parentId: nil, **)
108
123
  input[:description] = description if description
@@ -143,9 +158,9 @@ module LinearToonMcp
143
158
  return unless links
144
159
 
145
160
  links.each do |link|
146
- data = client.query(LINK_MUTATION, variables: {url: link["url"], issueId: issue_id, title: link["title"]})
161
+ data = client.query(LINK_MUTATION, variables: {url: link[:url], issueId: issue_id, title: link[:title]})
147
162
  next if data.dig("attachmentLinkURL", "success")
148
- raise Error, "Failed to attach link: #{link["url"]}"
163
+ raise Error, "Failed to attach link: #{link[:url]}"
149
164
  end
150
165
  end
151
166
  end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "toon"
4
+
5
+ module LinearToonMcp
6
+ module Tools
7
+ # List comments on a Linear issue in chronological order.
8
+ # Returns each comment's author, body, and timestamps.
9
+ class ListComments < MCP::Tool
10
+ description "List comments for a specific Linear issue"
11
+
12
+ annotations(
13
+ read_only_hint: true,
14
+ destructive_hint: false,
15
+ idempotent_hint: true
16
+ )
17
+
18
+ input_schema(
19
+ properties: {
20
+ issueId: {type: "string", description: "Issue ID or identifier (e.g., LIN-123)"}
21
+ },
22
+ required: ["issueId"],
23
+ additionalProperties: false
24
+ )
25
+
26
+ QUERY = <<~GRAPHQL
27
+ query($id: String!) {
28
+ issue(id: $id) {
29
+ comments(orderBy: createdAt) {
30
+ nodes {
31
+ id
32
+ body
33
+ createdAt
34
+ editedAt
35
+ user { id name }
36
+ }
37
+ pageInfo {
38
+ hasNextPage
39
+ endCursor
40
+ }
41
+ }
42
+ }
43
+ }
44
+ GRAPHQL
45
+
46
+ # standard:disable Naming/VariableName
47
+ class << self
48
+ # @param issueId [String] Linear issue ID or identifier (e.g., "LIN-123")
49
+ # @param server_context [Hash, nil] must contain +:client+ key with a {Client}
50
+ # @return [MCP::Tool::Response] TOON-encoded comments connection or error
51
+ def call(issueId:, server_context: nil)
52
+ client = server_context&.dig(:client) or raise Error, "client missing from server_context"
53
+ data = client.query(QUERY, variables: {id: issueId})
54
+ issue = data["issue"] or raise Error, "Issue not found: #{issueId}"
55
+ text = Toon.encode(issue["comments"])
56
+ MCP::Tool::Response.new([{type: "text", text:}])
57
+ rescue Error => e
58
+ MCP::Tool::Response.new([{type: "text", text: e.message}], error: true)
59
+ end
60
+ end
61
+ # standard:enable Naming/VariableName
62
+ end
63
+ end
64
+ end
@@ -115,10 +115,10 @@ module LinearToonMcp
115
115
  raise Error, "Issue update failed" unless result["success"]
116
116
 
117
117
  issue = result["issue"]
118
- replace_relations(client, id, kwargs)
119
- create_links(client, id, kwargs[:links])
118
+ warnings = post_update(client, id, **kwargs)
120
119
 
121
120
  text = Toon.encode(issue)
121
+ text += "\nWARNING (issue was updated): #{warnings.join("; ")}" if warnings.any?
122
122
  MCP::Tool::Response.new([{type: "text", text:}])
123
123
  rescue Error => e
124
124
  MCP::Tool::Response.new([{type: "text", text: e.message}], error: true)
@@ -126,6 +126,21 @@ module LinearToonMcp
126
126
 
127
127
  private
128
128
 
129
+ def post_update(client, issue_id, links: nil, **kwargs)
130
+ warnings = []
131
+ begin
132
+ replace_relations(client, issue_id, kwargs)
133
+ rescue Error => e
134
+ warnings << e.message
135
+ end
136
+ begin
137
+ create_links(client, issue_id, links)
138
+ rescue Error => e
139
+ warnings << e.message
140
+ end
141
+ warnings
142
+ end
143
+
129
144
  def resolve_team_id(client, issue_id, kwargs)
130
145
  return Resolvers.resolve_team(client, kwargs[:team]) if kwargs.key?(:team)
131
146
  return unless needs_team_id?(kwargs)
@@ -206,10 +221,10 @@ module LinearToonMcp
206
221
  return unless links
207
222
 
208
223
  links.each do |link|
209
- vars = {url: link["url"], issueId: issue_id, title: link["title"]}
224
+ vars = {url: link[:url], issueId: issue_id, title: link[:title]}
210
225
  data = client.query(LINK_MUTATION, variables: vars)
211
226
  next if data.dig("attachmentLinkURL", "success")
212
- raise Error, "Failed to attach link: #{link["url"]}"
227
+ raise Error, "Failed to attach link: #{link[:url]}"
213
228
  end
214
229
  end
215
230
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LinearToonMcp
4
- VERSION = "0.5.1"
4
+ VERSION = "0.6.0"
5
5
  end
@@ -7,6 +7,7 @@ require_relative "linear_toon_mcp/resolvers"
7
7
  require_relative "linear_toon_mcp/tools/get_issue"
8
8
  require_relative "linear_toon_mcp/tools/list_issues"
9
9
  require_relative "linear_toon_mcp/tools/create_comment"
10
+ require_relative "linear_toon_mcp/tools/list_comments"
10
11
  require_relative "linear_toon_mcp/tools/create_issue"
11
12
  require_relative "linear_toon_mcp/tools/update_issue"
12
13
  require_relative "linear_toon_mcp/tools/list_issue_statuses"
@@ -31,7 +32,7 @@ module LinearToonMcp
31
32
  name: "linear-toon-mcp",
32
33
  version: VERSION,
33
34
  description: "Manage Linear issues, projects, and teams",
34
- tools: [Tools::GetIssue, Tools::ListIssues, Tools::ListIssueStatuses, Tools::ListTeams, Tools::ListUsers, Tools::ListIssueLabels, Tools::ListProjects, Tools::ListCycles, Tools::GetProject, Tools::CreateComment, Tools::CreateIssue, Tools::UpdateIssue],
35
+ tools: [Tools::GetIssue, Tools::ListIssues, Tools::ListIssueStatuses, Tools::ListTeams, Tools::ListUsers, Tools::ListIssueLabels, Tools::ListProjects, Tools::ListCycles, Tools::GetProject, Tools::CreateComment, Tools::ListComments, Tools::CreateIssue, Tools::UpdateIssue],
35
36
  server_context: {client:}
36
37
  )
37
38
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: linear-toon-mcp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yevhenii Hurin
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: '0.6'
18
+ version: '0.11'
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: '0.6'
25
+ version: '0.11'
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: openssl
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -70,6 +70,7 @@ files:
70
70
  - lib/linear_toon_mcp/tools/create_issue.rb
71
71
  - lib/linear_toon_mcp/tools/get_issue.rb
72
72
  - lib/linear_toon_mcp/tools/get_project.rb
73
+ - lib/linear_toon_mcp/tools/list_comments.rb
73
74
  - lib/linear_toon_mcp/tools/list_cycles.rb
74
75
  - lib/linear_toon_mcp/tools/list_issue_labels.rb
75
76
  - lib/linear_toon_mcp/tools/list_issue_statuses.rb