linear-mcp-fast 0.1.0__tar.gz → 0.2.1__tar.gz
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.
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/PKG-INFO +7 -4
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/README.md +6 -3
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/pyproject.toml +1 -1
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/src/linear_mcp_fast/reader.py +2 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/src/linear_mcp_fast/server.py +175 -81
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/src/linear_mcp_fast.egg-info/PKG-INFO +7 -4
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/setup.cfg +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/src/linear_mcp_fast/__init__.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/src/linear_mcp_fast/__main__.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/src/linear_mcp_fast/store_detector.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/src/linear_mcp_fast.egg-info/SOURCES.txt +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/src/linear_mcp_fast.egg-info/dependency_links.txt +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/src/linear_mcp_fast.egg-info/entry_points.txt +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/src/linear_mcp_fast.egg-info/requires.txt +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/src/linear_mcp_fast.egg-info/top_level.txt +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_chromium_reader/ccl_chromium_reader/__init__.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_chromium_reader/ccl_chromium_reader/ccl_chromium_cache.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_chromium_reader/ccl_chromium_reader/ccl_chromium_filesystem.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_chromium_reader/ccl_chromium_reader/ccl_chromium_history.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_chromium_reader/ccl_chromium_reader/ccl_chromium_indexeddb.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_chromium_reader/ccl_chromium_reader/ccl_chromium_localstorage.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_chromium_reader/ccl_chromium_reader/ccl_chromium_notifications.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_chromium_reader/ccl_chromium_reader/ccl_chromium_profile_folder.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_chromium_reader/ccl_chromium_reader/ccl_chromium_sessionstorage.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_chromium_reader/ccl_chromium_reader/ccl_chromium_snss2.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_chromium_reader/ccl_chromium_reader/ccl_shared_proto_db_downloads.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_chromium_reader/ccl_chromium_reader/common.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_chromium_reader/ccl_chromium_reader/download_common.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_chromium_reader/ccl_chromium_reader/profile_folder_protocols.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_chromium_reader/ccl_chromium_reader/serialization_formats/__init__.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_chromium_reader/ccl_chromium_reader/serialization_formats/ccl_blink_value_deserializer.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_chromium_reader/ccl_chromium_reader/serialization_formats/ccl_easy_chromium_pickle.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_chromium_reader/ccl_chromium_reader/serialization_formats/ccl_protobuff.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_chromium_reader/ccl_chromium_reader/serialization_formats/ccl_v8_value_deserializer.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_chromium_reader/ccl_chromium_reader/storage_formats/__init__.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_chromium_reader/ccl_chromium_reader/storage_formats/ccl_leveldb.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_chromium_reader/tools_and_utilities/Chromium_dump_local_storage.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_chromium_reader/tools_and_utilities/Chromium_dump_session_storage.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_chromium_reader/tools_and_utilities/benchmark.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_chromium_reader/tools_and_utilities/ccl_chrome_audit.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_chromium_reader/tools_and_utilities/dump_indexeddb_details.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_chromium_reader/tools_and_utilities/dump_leveldb.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_simplesnappy/ccl_simplesnappy/__init__.py +0 -0
- {linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_simplesnappy/ccl_simplesnappy/ccl_simplesnappy.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: linear-mcp-fast
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Fast MCP server for Linear - reads from Linear.app's local cache on macOS
|
|
5
5
|
Author: everything-chalna
|
|
6
6
|
License-Expression: MIT
|
|
@@ -110,11 +110,14 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
|
110
110
|
|------|-------------|
|
|
111
111
|
| `list_issues` | List issues with filters (assignee, team, state, priority) |
|
|
112
112
|
| `get_issue` | Get issue details with comments |
|
|
113
|
-
| `
|
|
114
|
-
| `get_my_issues` | Get issues assigned to a user |
|
|
113
|
+
| `list_my_issues` | List issues assigned to a user |
|
|
115
114
|
| `list_teams` | List all teams |
|
|
115
|
+
| `get_team` | Get team details |
|
|
116
116
|
| `list_projects` | List all projects |
|
|
117
|
-
| `
|
|
117
|
+
| `get_project` | Get project details |
|
|
118
|
+
| `list_users` | List all users |
|
|
119
|
+
| `get_user` | Get user details |
|
|
120
|
+
| `list_issue_statuses` | List workflow states for a team |
|
|
118
121
|
|
|
119
122
|
### Writing (official Linear MCP)
|
|
120
123
|
|
|
@@ -86,11 +86,14 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
|
86
86
|
|------|-------------|
|
|
87
87
|
| `list_issues` | List issues with filters (assignee, team, state, priority) |
|
|
88
88
|
| `get_issue` | Get issue details with comments |
|
|
89
|
-
| `
|
|
90
|
-
| `get_my_issues` | Get issues assigned to a user |
|
|
89
|
+
| `list_my_issues` | List issues assigned to a user |
|
|
91
90
|
| `list_teams` | List all teams |
|
|
91
|
+
| `get_team` | Get team details |
|
|
92
92
|
| `list_projects` | List all projects |
|
|
93
|
-
| `
|
|
93
|
+
| `get_project` | Get project details |
|
|
94
|
+
| `list_users` | List all users |
|
|
95
|
+
| `get_user` | Get user details |
|
|
96
|
+
| `list_issue_statuses` | List workflow states for a team |
|
|
94
97
|
|
|
95
98
|
### Writing (official Linear MCP)
|
|
96
99
|
|
|
@@ -31,32 +31,13 @@ def get_reader() -> LinearLocalReader:
|
|
|
31
31
|
return _reader
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
def _parse_datetime(dt_value: Any) -> float | None:
|
|
35
|
-
"""Parse a datetime value to Unix timestamp."""
|
|
36
|
-
if dt_value is None:
|
|
37
|
-
return None
|
|
38
|
-
if isinstance(dt_value, (int, float)):
|
|
39
|
-
if dt_value > 1e12:
|
|
40
|
-
return dt_value / 1000
|
|
41
|
-
return dt_value
|
|
42
|
-
if isinstance(dt_value, str):
|
|
43
|
-
from datetime import datetime
|
|
44
|
-
try:
|
|
45
|
-
dt_str = dt_value.replace("Z", "+00:00")
|
|
46
|
-
dt = datetime.fromisoformat(dt_str)
|
|
47
|
-
return dt.timestamp()
|
|
48
|
-
except ValueError:
|
|
49
|
-
return None
|
|
50
|
-
return None
|
|
51
|
-
|
|
52
|
-
|
|
53
34
|
@mcp.tool()
|
|
54
35
|
def list_issues(
|
|
55
36
|
assignee: str | None = None,
|
|
56
37
|
team: str | None = None,
|
|
57
38
|
state_type: str | None = None,
|
|
58
39
|
priority: int | None = None,
|
|
59
|
-
limit: int =
|
|
40
|
+
limit: int | None = None,
|
|
60
41
|
) -> dict[str, Any]:
|
|
61
42
|
"""
|
|
62
43
|
List issues from local cache with optional filters.
|
|
@@ -66,13 +47,12 @@ def list_issues(
|
|
|
66
47
|
team: Filter by team key (e.g., 'UK')
|
|
67
48
|
state_type: Filter by state type (started, unstarted, completed, canceled, backlog)
|
|
68
49
|
priority: Filter by priority (1=Urgent, 2=High, 3=Medium, 4=Low)
|
|
69
|
-
limit: Maximum number of issues (default
|
|
50
|
+
limit: Maximum number of issues (default: all)
|
|
70
51
|
|
|
71
52
|
Returns:
|
|
72
53
|
Dictionary with issues array and totalCount
|
|
73
54
|
"""
|
|
74
55
|
reader = get_reader()
|
|
75
|
-
limit = min(limit, 100)
|
|
76
56
|
|
|
77
57
|
assignee_id = None
|
|
78
58
|
if assignee:
|
|
@@ -108,7 +88,7 @@ def list_issues(
|
|
|
108
88
|
filtered.append(issue)
|
|
109
89
|
|
|
110
90
|
total_count = len(filtered)
|
|
111
|
-
page = filtered[:limit]
|
|
91
|
+
page = filtered[:limit] if limit else filtered
|
|
112
92
|
|
|
113
93
|
results = []
|
|
114
94
|
for issue in page:
|
|
@@ -171,67 +151,23 @@ def get_issue(identifier: str) -> dict[str, Any] | None:
|
|
|
171
151
|
|
|
172
152
|
|
|
173
153
|
@mcp.tool()
|
|
174
|
-
def
|
|
175
|
-
"""
|
|
176
|
-
Search issues by title.
|
|
177
|
-
|
|
178
|
-
Args:
|
|
179
|
-
query: Search query (case-insensitive)
|
|
180
|
-
limit: Maximum results (default 20, max 100)
|
|
181
|
-
|
|
182
|
-
Returns:
|
|
183
|
-
Dictionary with matching issues
|
|
184
|
-
"""
|
|
185
|
-
reader = get_reader()
|
|
186
|
-
limit = min(limit, 100)
|
|
187
|
-
query_lower = query.lower()
|
|
188
|
-
|
|
189
|
-
all_issues = sorted(
|
|
190
|
-
reader.issues.values(),
|
|
191
|
-
key=lambda x: (x.get("priority") or 4, x.get("id", "")),
|
|
192
|
-
)
|
|
193
|
-
|
|
194
|
-
filtered = []
|
|
195
|
-
for issue in all_issues:
|
|
196
|
-
title = issue.get("title", "") or ""
|
|
197
|
-
identifier = issue.get("identifier", "") or ""
|
|
198
|
-
if query_lower in title.lower() or query_lower in identifier.lower():
|
|
199
|
-
filtered.append(issue)
|
|
200
|
-
|
|
201
|
-
match_count = len(filtered)
|
|
202
|
-
page = filtered[:limit]
|
|
203
|
-
|
|
204
|
-
results = []
|
|
205
|
-
for issue in page:
|
|
206
|
-
results.append({
|
|
207
|
-
"identifier": issue.get("identifier"),
|
|
208
|
-
"title": issue.get("title"),
|
|
209
|
-
"state": reader.get_state_name(issue.get("stateId", "")),
|
|
210
|
-
"stateType": reader.get_state_type(issue.get("stateId", "")),
|
|
211
|
-
})
|
|
212
|
-
|
|
213
|
-
return {"issues": results, "matchCount": match_count}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
@mcp.tool()
|
|
217
|
-
def get_my_issues(
|
|
154
|
+
def list_my_issues(
|
|
218
155
|
name: str,
|
|
219
156
|
state_type: str | None = None,
|
|
220
|
-
limit: int =
|
|
157
|
+
limit: int | None = None,
|
|
221
158
|
) -> dict[str, Any]:
|
|
222
159
|
"""
|
|
223
|
-
|
|
160
|
+
List issues assigned to a user.
|
|
224
161
|
|
|
225
162
|
Args:
|
|
226
163
|
name: User name to search for
|
|
227
164
|
state_type: Optional filter (started, unstarted, completed, canceled, backlog)
|
|
228
|
-
limit: Maximum issues (default
|
|
165
|
+
limit: Maximum issues (default: all)
|
|
229
166
|
|
|
230
167
|
Returns:
|
|
231
168
|
User info with their issues
|
|
232
169
|
"""
|
|
233
170
|
reader = get_reader()
|
|
234
|
-
limit = min(limit, 100)
|
|
235
171
|
|
|
236
172
|
user = reader.find_user(name)
|
|
237
173
|
if not user:
|
|
@@ -253,7 +189,7 @@ def get_my_issues(
|
|
|
253
189
|
if reader.get_state_type(i.get("stateId", "")) == state_type
|
|
254
190
|
]
|
|
255
191
|
|
|
256
|
-
page = all_issues[:limit]
|
|
192
|
+
page = all_issues[:limit] if limit else all_issues
|
|
257
193
|
|
|
258
194
|
results = []
|
|
259
195
|
for issue in page:
|
|
@@ -342,24 +278,182 @@ def list_projects(team: str | None = None) -> list[dict[str, Any]]:
|
|
|
342
278
|
|
|
343
279
|
|
|
344
280
|
@mcp.tool()
|
|
345
|
-
def
|
|
281
|
+
def get_team(team: str) -> dict[str, Any] | None:
|
|
282
|
+
"""
|
|
283
|
+
Get team details by key or name.
|
|
284
|
+
|
|
285
|
+
Args:
|
|
286
|
+
team: Team key (e.g., 'UK') or name
|
|
287
|
+
|
|
288
|
+
Returns:
|
|
289
|
+
Team details or None if not found
|
|
290
|
+
"""
|
|
291
|
+
reader = get_reader()
|
|
292
|
+
team_obj = reader.find_team(team)
|
|
293
|
+
|
|
294
|
+
if not team_obj:
|
|
295
|
+
return None
|
|
296
|
+
|
|
297
|
+
issue_count = sum(
|
|
298
|
+
1 for i in reader.issues.values() if i.get("teamId") == team_obj["id"]
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
# Count by state type
|
|
302
|
+
state_counts: dict[str, int] = {}
|
|
303
|
+
for issue in reader.issues.values():
|
|
304
|
+
if issue.get("teamId") == team_obj["id"]:
|
|
305
|
+
state_type = reader.get_state_type(issue.get("stateId", ""))
|
|
306
|
+
state_counts[state_type] = state_counts.get(state_type, 0) + 1
|
|
307
|
+
|
|
308
|
+
return {
|
|
309
|
+
"id": team_obj.get("id"),
|
|
310
|
+
"key": team_obj.get("key"),
|
|
311
|
+
"name": team_obj.get("name"),
|
|
312
|
+
"description": team_obj.get("description"),
|
|
313
|
+
"issueCount": issue_count,
|
|
314
|
+
"issuesByState": state_counts,
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
@mcp.tool()
|
|
319
|
+
def get_project(name: str) -> dict[str, Any] | None:
|
|
320
|
+
"""
|
|
321
|
+
Get project details by name.
|
|
322
|
+
|
|
323
|
+
Args:
|
|
324
|
+
name: Project name (partial match)
|
|
325
|
+
|
|
326
|
+
Returns:
|
|
327
|
+
Project details or None if not found
|
|
328
|
+
"""
|
|
329
|
+
reader = get_reader()
|
|
330
|
+
|
|
331
|
+
# Find project by name (partial match)
|
|
332
|
+
name_lower = name.lower()
|
|
333
|
+
project = None
|
|
334
|
+
for p in reader.projects.values():
|
|
335
|
+
if name_lower in (p.get("name", "") or "").lower():
|
|
336
|
+
project = p
|
|
337
|
+
break
|
|
338
|
+
|
|
339
|
+
if not project:
|
|
340
|
+
return None
|
|
341
|
+
|
|
342
|
+
issue_count = sum(
|
|
343
|
+
1 for i in reader.issues.values() if i.get("projectId") == project["id"]
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
# Count by state type
|
|
347
|
+
state_counts: dict[str, int] = {}
|
|
348
|
+
for issue in reader.issues.values():
|
|
349
|
+
if issue.get("projectId") == project["id"]:
|
|
350
|
+
state_type = reader.get_state_type(issue.get("stateId", ""))
|
|
351
|
+
state_counts[state_type] = state_counts.get(state_type, 0) + 1
|
|
352
|
+
|
|
353
|
+
return {
|
|
354
|
+
"id": project.get("id"),
|
|
355
|
+
"name": project.get("name"),
|
|
356
|
+
"description": project.get("description"),
|
|
357
|
+
"state": project.get("state"),
|
|
358
|
+
"startDate": project.get("startDate"),
|
|
359
|
+
"targetDate": project.get("targetDate"),
|
|
360
|
+
"issueCount": issue_count,
|
|
361
|
+
"issuesByState": state_counts,
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
@mcp.tool()
|
|
366
|
+
def list_users() -> list[dict[str, Any]]:
|
|
367
|
+
"""
|
|
368
|
+
List all users in the workspace.
|
|
369
|
+
|
|
370
|
+
Returns:
|
|
371
|
+
List of users with basic info
|
|
372
|
+
"""
|
|
373
|
+
reader = get_reader()
|
|
374
|
+
results = []
|
|
375
|
+
|
|
376
|
+
for user in reader.users.values():
|
|
377
|
+
issue_count = sum(
|
|
378
|
+
1 for i in reader.issues.values() if i.get("assigneeId") == user["id"]
|
|
379
|
+
)
|
|
380
|
+
results.append({
|
|
381
|
+
"id": user.get("id"),
|
|
382
|
+
"name": user.get("name"),
|
|
383
|
+
"email": user.get("email"),
|
|
384
|
+
"displayName": user.get("displayName"),
|
|
385
|
+
"assignedIssueCount": issue_count,
|
|
386
|
+
})
|
|
387
|
+
|
|
388
|
+
results.sort(key=lambda x: x.get("name", "") or "")
|
|
389
|
+
return results
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
@mcp.tool()
|
|
393
|
+
def get_user(name: str) -> dict[str, Any] | None:
|
|
346
394
|
"""
|
|
347
|
-
Get
|
|
395
|
+
Get user details by name.
|
|
396
|
+
|
|
397
|
+
Args:
|
|
398
|
+
name: User name (partial match)
|
|
348
399
|
|
|
349
400
|
Returns:
|
|
350
|
-
|
|
401
|
+
User details or None if not found
|
|
351
402
|
"""
|
|
352
403
|
reader = get_reader()
|
|
353
|
-
|
|
404
|
+
user = reader.find_user(name)
|
|
354
405
|
|
|
355
|
-
|
|
406
|
+
if not user:
|
|
407
|
+
return None
|
|
408
|
+
|
|
409
|
+
# Count issues by state
|
|
356
410
|
state_counts: dict[str, int] = {}
|
|
357
411
|
for issue in reader.issues.values():
|
|
358
|
-
|
|
359
|
-
|
|
412
|
+
if issue.get("assigneeId") == user["id"]:
|
|
413
|
+
state_type = reader.get_state_type(issue.get("stateId", ""))
|
|
414
|
+
state_counts[state_type] = state_counts.get(state_type, 0) + 1
|
|
415
|
+
|
|
416
|
+
return {
|
|
417
|
+
"id": user.get("id"),
|
|
418
|
+
"name": user.get("name"),
|
|
419
|
+
"email": user.get("email"),
|
|
420
|
+
"displayName": user.get("displayName"),
|
|
421
|
+
"assignedIssueCount": sum(state_counts.values()),
|
|
422
|
+
"issuesByState": state_counts,
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
@mcp.tool()
|
|
427
|
+
def list_issue_statuses(team: str) -> list[dict[str, Any]]:
|
|
428
|
+
"""
|
|
429
|
+
List available issue statuses for a team.
|
|
430
|
+
|
|
431
|
+
Args:
|
|
432
|
+
team: Team key (e.g., 'UK')
|
|
360
433
|
|
|
361
|
-
|
|
362
|
-
|
|
434
|
+
Returns:
|
|
435
|
+
List of workflow states
|
|
436
|
+
"""
|
|
437
|
+
reader = get_reader()
|
|
438
|
+
|
|
439
|
+
team_obj = reader.find_team(team)
|
|
440
|
+
if not team_obj:
|
|
441
|
+
return []
|
|
442
|
+
|
|
443
|
+
# Get states for this team
|
|
444
|
+
results = []
|
|
445
|
+
for state in reader.states.values():
|
|
446
|
+
if state.get("teamId") == team_obj["id"]:
|
|
447
|
+
results.append({
|
|
448
|
+
"id": state.get("id"),
|
|
449
|
+
"name": state.get("name"),
|
|
450
|
+
"type": state.get("type"),
|
|
451
|
+
"color": state.get("color"),
|
|
452
|
+
"position": state.get("position"),
|
|
453
|
+
})
|
|
454
|
+
|
|
455
|
+
results.sort(key=lambda x: (x.get("position") or 0))
|
|
456
|
+
return results
|
|
363
457
|
|
|
364
458
|
|
|
365
459
|
def main():
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: linear-mcp-fast
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Fast MCP server for Linear - reads from Linear.app's local cache on macOS
|
|
5
5
|
Author: everything-chalna
|
|
6
6
|
License-Expression: MIT
|
|
@@ -110,11 +110,14 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
|
110
110
|
|------|-------------|
|
|
111
111
|
| `list_issues` | List issues with filters (assignee, team, state, priority) |
|
|
112
112
|
| `get_issue` | Get issue details with comments |
|
|
113
|
-
| `
|
|
114
|
-
| `get_my_issues` | Get issues assigned to a user |
|
|
113
|
+
| `list_my_issues` | List issues assigned to a user |
|
|
115
114
|
| `list_teams` | List all teams |
|
|
115
|
+
| `get_team` | Get team details |
|
|
116
116
|
| `list_projects` | List all projects |
|
|
117
|
-
| `
|
|
117
|
+
| `get_project` | Get project details |
|
|
118
|
+
| `list_users` | List all users |
|
|
119
|
+
| `get_user` | Get user details |
|
|
120
|
+
| `list_issue_statuses` | List workflow states for a team |
|
|
118
121
|
|
|
119
122
|
### Writing (official Linear MCP)
|
|
120
123
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/src/linear_mcp_fast.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/src/linear_mcp_fast.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{linear_mcp_fast-0.1.0 → linear_mcp_fast-0.2.1}/vendor/ccl_simplesnappy/ccl_simplesnappy/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|