linear-toon-mcp 0.4.0 → 0.5.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: dc4a8872f9db60b36c89019d376e06b28c95ea1d881c62996c0cf05e65e8ccb5
4
- data.tar.gz: 479e37c017575c68fda311020066518211956fe2416d76c16e337114d20d9cc0
3
+ metadata.gz: b7241fefeb39d4de3f8649fa66bede65615fa0eda60aa1206f121f3c2e30d0d8
4
+ data.tar.gz: d0eefcd97e9ff4fd27ca48efde69eeb6124a082b81f619671c5a67c8d3cc817e
5
5
  SHA512:
6
- metadata.gz: e4967b288c7ee386c448b03acecc0c74b9d7134c88efa23179341a7ab6433e6e58372a84df06a0a835c60bde9522d699a0f57572e56365541521a1161f8e52e5
7
- data.tar.gz: '078f01ebb0c2b14ba592e065b3bc131768e1ec1d51df887cbae0abd4dcb8b32f48c89e15d54b027d889d6b88ba524c95f8a9ff40685853d1b9244d496f122ffa'
6
+ metadata.gz: 3275b9582f4ea6d2a800e2dbc08f64e81e82932a5ec9a545ccdc7dea5d3935fd65a18aec825c464e17cbd724dfc04f239f9cb187a5c70cb2df25299576cdbb9d
7
+ data.tar.gz: b65c95f035164b0ea5eddc6f703716779040828e20d42b889992244de18bb95053178933af1a7a5f9406a4c567d8a6fed80ed8966a04641a8700ff9dec122b8f
data/README.md CHANGED
@@ -37,7 +37,7 @@ Get your API key from [Linear Settings > API](https://linear.app/settings/api).
37
37
  ### Claude Code
38
38
 
39
39
  ```bash
40
- claude mcp add -e LINEAR_API_KEY=lin_api_xxxxx linear-toon -- linear-toon-mcp
40
+ claude mcp add linear-toon -e LINEAR_API_KEY=lin_api_xxxxx -- linear-toon-mcp
41
41
  ```
42
42
 
43
43
  ## Tools
@@ -52,6 +52,7 @@ claude mcp add -e LINEAR_API_KEY=lin_api_xxxxx linear-toon -- linear-toon-mcp
52
52
  | `list_issue_labels` | List issue labels, optionally scoped to a team. Returns label id and name. |
53
53
  | `list_projects` | List projects, optionally scoped to a team. Returns project id, name, and state. |
54
54
  | `list_cycles` | List cycles for a team. Returns cycle id, name, number, startsAt, and endsAt. Requires team name or UUID. |
55
+ | `get_project` | Retrieve a specific project by name, ID, or slug. Returns project details including state, priority, dates, progress, and lead. Optional includes for members, milestones, and resources. |
55
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. |
56
57
  | `update_issue` | Update an existing Linear issue by ID. Supports partial updates, null to remove fields, and relation replacement. |
57
58
  | `create_comment` | Create a comment on a Linear issue. Supports Markdown content and threaded replies via parentId. |
@@ -110,12 +110,18 @@ module LinearToonMcp
110
110
  end
111
111
 
112
112
  # @param client [Client]
113
- # @param value [String] project UUID or name
113
+ # @param value [String] project UUID, name, or slug
114
114
  # @return [String] project UUID
115
115
  # @raise [Error] when project not found
116
116
  def resolve_project(client, value)
117
117
  return value if value.match?(UUID_RE)
118
+
119
+ # Try name first, then slug
118
120
  data = client.query(PROJECT_QUERY, variables: {filter: {name: {eqIgnoreCase: value}}})
121
+ id = data.dig("projects", "nodes", 0, "id")
122
+ return id if id
123
+
124
+ data = client.query(PROJECT_QUERY, variables: {filter: {slugId: {eqIgnoreCase: value}}})
119
125
  data.dig("projects", "nodes", 0, "id") or raise Error, "Project not found: #{value}"
120
126
  end
121
127
 
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "toon"
4
+
5
+ module LinearToonMcp
6
+ module Tools
7
+ # Fetch a single Linear project by ID, name, or slug and return it as TOON.
8
+ # Supports optional includes for members, milestones, and resources.
9
+ class GetProject < MCP::Tool
10
+ description "Retrieve details of a specific project in Linear"
11
+
12
+ annotations(
13
+ read_only_hint: true,
14
+ destructive_hint: false,
15
+ idempotent_hint: true
16
+ )
17
+
18
+ input_schema(
19
+ properties: {
20
+ query: {type: "string", description: "Project name, ID, or slug"},
21
+ includeMembers: {type: "boolean", description: "Include project members (default: false)"},
22
+ includeMilestones: {type: "boolean", description: "Include milestones (default: false)"},
23
+ includeResources: {type: "boolean", description: "Include resources (documents) (default: false)"}
24
+ },
25
+ required: ["query"],
26
+ additionalProperties: false
27
+ )
28
+
29
+ BASE_FIELDS = <<~GRAPHQL
30
+ id
31
+ name
32
+ slugId
33
+ icon
34
+ color
35
+ url
36
+ description
37
+ state
38
+ priority
39
+ priorityLabel
40
+ startDate
41
+ targetDate
42
+ createdAt
43
+ updatedAt
44
+ archivedAt
45
+ progress
46
+ scope
47
+ completedScopeHistory
48
+ lead { id name }
49
+ status { id name }
50
+ teams { nodes { id name } }
51
+ labels { nodes { id name } }
52
+ initiatives { nodes { id name } }
53
+ GRAPHQL
54
+
55
+ MEMBERS_FIELDS = "members { nodes { id name email } }"
56
+ MILESTONES_FIELDS = "projectMilestones { nodes { id name targetDate } }"
57
+ RESOURCES_FIELDS = "documents { nodes { id title } }"
58
+
59
+ # standard:disable Naming/VariableName
60
+ class << self
61
+ # @param query [String] Project ID, name, or slug
62
+ # @param includeMembers [Boolean] Include project members
63
+ # @param includeMilestones [Boolean] Include project milestones
64
+ # @param includeResources [Boolean] Include documents
65
+ # @param server_context [Hash, nil] must contain +:client+ key with a {Client}
66
+ # @return [MCP::Tool::Response] TOON-encoded project or error
67
+ def call(query:, includeMembers: false, includeMilestones: false, includeResources: false, server_context: nil)
68
+ client = server_context&.dig(:client) or raise Error, "client missing from server_context"
69
+ project_id = Resolvers.resolve_project(client, query)
70
+ graphql = build_query(includeMembers:, includeMilestones:, includeResources:)
71
+ data = client.query(graphql, variables: {id: project_id})
72
+ project = data["project"] or raise Error, "Project not found: #{query}"
73
+ text = Toon.encode(project)
74
+ MCP::Tool::Response.new([{type: "text", text:}])
75
+ rescue Error => e
76
+ MCP::Tool::Response.new([{type: "text", text: e.message}], error: true)
77
+ end
78
+
79
+ private
80
+
81
+ def build_query(includeMembers:, includeMilestones:, includeResources:)
82
+ fields = [BASE_FIELDS.strip]
83
+ fields << MEMBERS_FIELDS if includeMembers
84
+ fields << MILESTONES_FIELDS if includeMilestones
85
+ fields << RESOURCES_FIELDS if includeResources
86
+
87
+ <<~GRAPHQL
88
+ query($id: String!) {
89
+ project(id: $id) {
90
+ #{fields.join("\n ")}
91
+ }
92
+ }
93
+ GRAPHQL
94
+ end
95
+ end
96
+ # standard:enable Naming/VariableName
97
+ end
98
+ end
99
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LinearToonMcp
4
- VERSION = "0.4.0"
4
+ VERSION = "0.5.0"
5
5
  end
@@ -15,6 +15,7 @@ require_relative "linear_toon_mcp/tools/list_users"
15
15
  require_relative "linear_toon_mcp/tools/list_issue_labels"
16
16
  require_relative "linear_toon_mcp/tools/list_projects"
17
17
  require_relative "linear_toon_mcp/tools/list_cycles"
18
+ require_relative "linear_toon_mcp/tools/get_project"
18
19
 
19
20
  # Token-efficient MCP server for Linear. Wraps Linear's GraphQL API
20
21
  # and returns TOON-formatted responses for ~40-60% token savings.
@@ -30,7 +31,7 @@ module LinearToonMcp
30
31
  name: "linear-toon-mcp",
31
32
  version: VERSION,
32
33
  description: "Manage Linear issues, projects, and teams",
33
- tools: [Tools::GetIssue, Tools::ListIssues, Tools::ListIssueStatuses, Tools::ListTeams, Tools::ListUsers, Tools::ListIssueLabels, Tools::ListProjects, Tools::ListCycles, Tools::CreateComment, Tools::CreateIssue, Tools::UpdateIssue],
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],
34
35
  server_context: {client:}
35
36
  )
36
37
  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.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yevhenii Hurin
@@ -69,6 +69,7 @@ files:
69
69
  - lib/linear_toon_mcp/tools/create_comment.rb
70
70
  - lib/linear_toon_mcp/tools/create_issue.rb
71
71
  - lib/linear_toon_mcp/tools/get_issue.rb
72
+ - lib/linear_toon_mcp/tools/get_project.rb
72
73
  - lib/linear_toon_mcp/tools/list_cycles.rb
73
74
  - lib/linear_toon_mcp/tools/list_issue_labels.rb
74
75
  - lib/linear_toon_mcp/tools/list_issue_statuses.rb