iflow-mcp_excelsier-things3-enhanced-mcp 1.0.0__py3-none-any.whl
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.
- iflow_mcp_excelsier_things3_enhanced_mcp-1.0.0.dist-info/METADATA +444 -0
- iflow_mcp_excelsier_things3_enhanced_mcp-1.0.0.dist-info/RECORD +20 -0
- iflow_mcp_excelsier_things3_enhanced_mcp-1.0.0.dist-info/WHEEL +4 -0
- iflow_mcp_excelsier_things3_enhanced_mcp-1.0.0.dist-info/entry_points.txt +2 -0
- iflow_mcp_excelsier_things3_enhanced_mcp-1.0.0.dist-info/licenses/LICENSE +24 -0
- things_mcp/__init__.py +5 -0
- things_mcp/applescript_bridge.py +335 -0
- things_mcp/cache.py +240 -0
- things_mcp/config.py +120 -0
- things_mcp/fast_server.py +633 -0
- things_mcp/formatters.py +128 -0
- things_mcp/handlers.py +601 -0
- things_mcp/logging_config.py +218 -0
- things_mcp/mcp_tools.py +465 -0
- things_mcp/simple_server.py +687 -0
- things_mcp/simple_url_scheme.py +230 -0
- things_mcp/tag_handler.py +111 -0
- things_mcp/things_server.py +106 -0
- things_mcp/url_scheme.py +318 -0
- things_mcp/utils.py +360 -0
things_mcp/formatters.py
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import things
|
|
3
|
+
|
|
4
|
+
logger = logging.getLogger(__name__)
|
|
5
|
+
|
|
6
|
+
def format_todo(todo: dict) -> str:
|
|
7
|
+
"""Helper function to format a single todo into a readable string."""
|
|
8
|
+
logger.debug(f"Formatting todo: {todo}")
|
|
9
|
+
todo_text = f"Title: {todo['title']}"
|
|
10
|
+
|
|
11
|
+
# Add UUID for reference
|
|
12
|
+
todo_text += f"\nUUID: {todo['uuid']}"
|
|
13
|
+
|
|
14
|
+
# Add type
|
|
15
|
+
todo_text += f"\nType: {todo['type']}"
|
|
16
|
+
|
|
17
|
+
# Add status if present
|
|
18
|
+
if todo.get('status'):
|
|
19
|
+
todo_text += f"\nStatus: {todo['status']}"
|
|
20
|
+
|
|
21
|
+
# Add start/list location
|
|
22
|
+
if todo.get('start'):
|
|
23
|
+
todo_text += f"\nList: {todo['start']}"
|
|
24
|
+
|
|
25
|
+
# Add dates
|
|
26
|
+
if todo.get('start_date'):
|
|
27
|
+
todo_text += f"\nStart Date: {todo['start_date']}"
|
|
28
|
+
if todo.get('deadline'):
|
|
29
|
+
todo_text += f"\nDeadline: {todo['deadline']}"
|
|
30
|
+
if todo.get('stop_date'): # Completion date
|
|
31
|
+
todo_text += f"\nCompleted: {todo['stop_date']}"
|
|
32
|
+
|
|
33
|
+
# Add notes if present
|
|
34
|
+
if todo.get('notes'):
|
|
35
|
+
todo_text += f"\nNotes: {todo['notes']}"
|
|
36
|
+
|
|
37
|
+
# Add project info if present
|
|
38
|
+
if todo.get('project'):
|
|
39
|
+
try:
|
|
40
|
+
project = things.get(todo['project'])
|
|
41
|
+
if project:
|
|
42
|
+
todo_text += f"\nProject: {project['title']}"
|
|
43
|
+
except Exception:
|
|
44
|
+
pass
|
|
45
|
+
|
|
46
|
+
# Add area info if present
|
|
47
|
+
if todo.get('area'):
|
|
48
|
+
try:
|
|
49
|
+
area = things.get(todo['area'])
|
|
50
|
+
if area:
|
|
51
|
+
todo_text += f"\nArea: {area['title']}"
|
|
52
|
+
except Exception:
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
# Add tags if present
|
|
56
|
+
if todo.get('tags'):
|
|
57
|
+
todo_text += f"\nTags: {', '.join(todo['tags'])}"
|
|
58
|
+
|
|
59
|
+
# Add checklist if present and contains items
|
|
60
|
+
if isinstance(todo.get('checklist'), list):
|
|
61
|
+
todo_text += "\nChecklist:"
|
|
62
|
+
for item in todo['checklist']:
|
|
63
|
+
status = "✓" if item['status'] == 'completed' else "□"
|
|
64
|
+
todo_text += f"\n {status} {item['title']}"
|
|
65
|
+
|
|
66
|
+
return todo_text
|
|
67
|
+
|
|
68
|
+
def format_project(project: dict, include_items: bool = False) -> str:
|
|
69
|
+
"""Helper function to format a single project."""
|
|
70
|
+
project_text = f"Title: {project['title']}\nUUID: {project['uuid']}"
|
|
71
|
+
|
|
72
|
+
if project.get('area'):
|
|
73
|
+
try:
|
|
74
|
+
area = things.get(project['area'])
|
|
75
|
+
if area:
|
|
76
|
+
project_text += f"\nArea: {area['title']}"
|
|
77
|
+
except Exception:
|
|
78
|
+
pass
|
|
79
|
+
|
|
80
|
+
if project.get('notes'):
|
|
81
|
+
project_text += f"\nNotes: {project['notes']}"
|
|
82
|
+
|
|
83
|
+
if include_items:
|
|
84
|
+
todos = things.todos(project=project['uuid'])
|
|
85
|
+
if todos:
|
|
86
|
+
project_text += "\n\nTasks:"
|
|
87
|
+
for todo in todos:
|
|
88
|
+
project_text += f"\n- {todo['title']}"
|
|
89
|
+
|
|
90
|
+
return project_text
|
|
91
|
+
|
|
92
|
+
def format_area(area: dict, include_items: bool = False) -> str:
|
|
93
|
+
"""Helper function to format a single area."""
|
|
94
|
+
area_text = f"Title: {area['title']}\nUUID: {area['uuid']}"
|
|
95
|
+
|
|
96
|
+
if area.get('notes'):
|
|
97
|
+
area_text += f"\nNotes: {area['notes']}"
|
|
98
|
+
|
|
99
|
+
if include_items:
|
|
100
|
+
projects = things.projects(area=area['uuid'])
|
|
101
|
+
if projects:
|
|
102
|
+
area_text += "\n\nProjects:"
|
|
103
|
+
for project in projects:
|
|
104
|
+
area_text += f"\n- {project['title']}"
|
|
105
|
+
|
|
106
|
+
todos = things.todos(area=area['uuid'])
|
|
107
|
+
if todos:
|
|
108
|
+
area_text += "\n\nTasks:"
|
|
109
|
+
for todo in todos:
|
|
110
|
+
area_text += f"\n- {todo['title']}"
|
|
111
|
+
|
|
112
|
+
return area_text
|
|
113
|
+
|
|
114
|
+
def format_tag(tag: dict, include_items: bool = False) -> str:
|
|
115
|
+
"""Helper function to format a single tag."""
|
|
116
|
+
tag_text = f"Title: {tag['title']}\nUUID: {tag['uuid']}"
|
|
117
|
+
|
|
118
|
+
if tag.get('shortcut'):
|
|
119
|
+
tag_text += f"\nShortcut: {tag['shortcut']}"
|
|
120
|
+
|
|
121
|
+
if include_items:
|
|
122
|
+
todos = things.todos(tag=tag['title'])
|
|
123
|
+
if todos:
|
|
124
|
+
tag_text += "\n\nTagged Items:"
|
|
125
|
+
for todo in todos:
|
|
126
|
+
tag_text += f"\n- {todo['title']}"
|
|
127
|
+
|
|
128
|
+
return tag_text
|