couchloop-eq-mcp 1.0.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.
Files changed (222) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +358 -0
  3. package/assets/logo/README.md +12 -0
  4. package/assets/logo/couchloop_EQ-IconLogo.png +0 -0
  5. package/dist/auth/middleware.d.ts +8 -0
  6. package/dist/auth/middleware.d.ts.map +1 -0
  7. package/dist/auth/middleware.js +59 -0
  8. package/dist/auth/middleware.js.map +1 -0
  9. package/dist/clients/shrinkChatClient.d.ts +195 -0
  10. package/dist/clients/shrinkChatClient.d.ts.map +1 -0
  11. package/dist/clients/shrinkChatClient.js +349 -0
  12. package/dist/clients/shrinkChatClient.js.map +1 -0
  13. package/dist/db/client.d.ts +23 -0
  14. package/dist/db/client.d.ts.map +1 -0
  15. package/dist/db/client.js +78 -0
  16. package/dist/db/client.js.map +1 -0
  17. package/dist/db/migrate.d.ts +4 -0
  18. package/dist/db/migrate.d.ts.map +1 -0
  19. package/dist/db/migrate.js +34 -0
  20. package/dist/db/migrate.js.map +1 -0
  21. package/dist/db/migrations/schema.d.ts +1074 -0
  22. package/dist/db/migrations/schema.d.ts.map +1 -0
  23. package/dist/db/migrations/schema.js +160 -0
  24. package/dist/db/migrations/schema.js.map +1 -0
  25. package/dist/db/schema.d.ts +1213 -0
  26. package/dist/db/schema.d.ts.map +1 -0
  27. package/dist/db/schema.js +157 -0
  28. package/dist/db/schema.js.map +1 -0
  29. package/dist/db/seed.d.ts +4 -0
  30. package/dist/db/seed.d.ts.map +1 -0
  31. package/dist/db/seed.js +57 -0
  32. package/dist/db/seed.js.map +1 -0
  33. package/dist/db/seedOAuth.d.ts +4 -0
  34. package/dist/db/seedOAuth.d.ts.map +1 -0
  35. package/dist/db/seedOAuth.js +76 -0
  36. package/dist/db/seedOAuth.js.map +1 -0
  37. package/dist/index.d.ts +3 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +93 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/resources/index.d.ts +11 -0
  42. package/dist/resources/index.d.ts.map +1 -0
  43. package/dist/resources/index.js +56 -0
  44. package/dist/resources/index.js.map +1 -0
  45. package/dist/resources/journey-status.d.ts +2 -0
  46. package/dist/resources/journey-status.d.ts.map +1 -0
  47. package/dist/resources/journey-status.js +42 -0
  48. package/dist/resources/journey-status.js.map +1 -0
  49. package/dist/resources/session-summary.d.ts +2 -0
  50. package/dist/resources/session-summary.d.ts.map +1 -0
  51. package/dist/resources/session-summary.js +85 -0
  52. package/dist/resources/session-summary.js.map +1 -0
  53. package/dist/resources/user-context.d.ts +2 -0
  54. package/dist/resources/user-context.d.ts.map +1 -0
  55. package/dist/resources/user-context.js +79 -0
  56. package/dist/resources/user-context.js.map +1 -0
  57. package/dist/server/index.d.ts +3 -0
  58. package/dist/server/index.d.ts.map +1 -0
  59. package/dist/server/index.js +385 -0
  60. package/dist/server/index.js.map +1 -0
  61. package/dist/server/middleware/auth.d.ts +30 -0
  62. package/dist/server/middleware/auth.d.ts.map +1 -0
  63. package/dist/server/middleware/auth.js +157 -0
  64. package/dist/server/middleware/auth.js.map +1 -0
  65. package/dist/server/oauth/anomalyDetection.d.ts +146 -0
  66. package/dist/server/oauth/anomalyDetection.d.ts.map +1 -0
  67. package/dist/server/oauth/anomalyDetection.js +405 -0
  68. package/dist/server/oauth/anomalyDetection.js.map +1 -0
  69. package/dist/server/oauth/authServer.d.ts +61 -0
  70. package/dist/server/oauth/authServer.d.ts.map +1 -0
  71. package/dist/server/oauth/authServer.js +283 -0
  72. package/dist/server/oauth/authServer.js.map +1 -0
  73. package/dist/server/oauth/dpop.d.ts +135 -0
  74. package/dist/server/oauth/dpop.d.ts.map +1 -0
  75. package/dist/server/oauth/dpop.js +338 -0
  76. package/dist/server/oauth/dpop.js.map +1 -0
  77. package/dist/server/oauth/gdpr/consent.d.ts +173 -0
  78. package/dist/server/oauth/gdpr/consent.d.ts.map +1 -0
  79. package/dist/server/oauth/gdpr/consent.js +388 -0
  80. package/dist/server/oauth/gdpr/consent.js.map +1 -0
  81. package/dist/server/oauth/gdpr/dataPortability.d.ts +214 -0
  82. package/dist/server/oauth/gdpr/dataPortability.d.ts.map +1 -0
  83. package/dist/server/oauth/gdpr/dataPortability.js +486 -0
  84. package/dist/server/oauth/gdpr/dataPortability.js.map +1 -0
  85. package/dist/server/oauth/gdpr/index.d.ts +103 -0
  86. package/dist/server/oauth/gdpr/index.d.ts.map +1 -0
  87. package/dist/server/oauth/gdpr/index.js +273 -0
  88. package/dist/server/oauth/gdpr/index.js.map +1 -0
  89. package/dist/server/oauth/gdpr/rightToErasure.d.ts +184 -0
  90. package/dist/server/oauth/gdpr/rightToErasure.d.ts.map +1 -0
  91. package/dist/server/oauth/gdpr/rightToErasure.js +527 -0
  92. package/dist/server/oauth/gdpr/rightToErasure.js.map +1 -0
  93. package/dist/server/oauth/monitoring/securityMonitor.d.ts +218 -0
  94. package/dist/server/oauth/monitoring/securityMonitor.d.ts.map +1 -0
  95. package/dist/server/oauth/monitoring/securityMonitor.js +615 -0
  96. package/dist/server/oauth/monitoring/securityMonitor.js.map +1 -0
  97. package/dist/server/oauth/pkce.d.ts +61 -0
  98. package/dist/server/oauth/pkce.d.ts.map +1 -0
  99. package/dist/server/oauth/pkce.js +157 -0
  100. package/dist/server/oauth/pkce.js.map +1 -0
  101. package/dist/server/oauth/providers/base.d.ts +147 -0
  102. package/dist/server/oauth/providers/base.d.ts.map +1 -0
  103. package/dist/server/oauth/providers/base.js +312 -0
  104. package/dist/server/oauth/providers/base.js.map +1 -0
  105. package/dist/server/oauth/providers/github.d.ts +55 -0
  106. package/dist/server/oauth/providers/github.d.ts.map +1 -0
  107. package/dist/server/oauth/providers/github.js +225 -0
  108. package/dist/server/oauth/providers/github.js.map +1 -0
  109. package/dist/server/oauth/providers/google.d.ts +49 -0
  110. package/dist/server/oauth/providers/google.d.ts.map +1 -0
  111. package/dist/server/oauth/providers/google.js +153 -0
  112. package/dist/server/oauth/providers/google.js.map +1 -0
  113. package/dist/server/oauth/providers/index.d.ts +9 -0
  114. package/dist/server/oauth/providers/index.d.ts.map +1 -0
  115. package/dist/server/oauth/providers/index.js +24 -0
  116. package/dist/server/oauth/providers/index.js.map +1 -0
  117. package/dist/server/oauth/refreshTokenRotation.d.ts +114 -0
  118. package/dist/server/oauth/refreshTokenRotation.d.ts.map +1 -0
  119. package/dist/server/oauth/refreshTokenRotation.js +344 -0
  120. package/dist/server/oauth/refreshTokenRotation.js.map +1 -0
  121. package/dist/server/oauth/security.d.ts +101 -0
  122. package/dist/server/oauth/security.d.ts.map +1 -0
  123. package/dist/server/oauth/security.js +268 -0
  124. package/dist/server/oauth/security.js.map +1 -0
  125. package/dist/server/oauth/tokenEncryption.d.ts +80 -0
  126. package/dist/server/oauth/tokenEncryption.d.ts.map +1 -0
  127. package/dist/server/oauth/tokenEncryption.js +218 -0
  128. package/dist/server/oauth/tokenEncryption.js.map +1 -0
  129. package/dist/tools/checkpoint.d.ts +35 -0
  130. package/dist/tools/checkpoint.d.ts.map +1 -0
  131. package/dist/tools/checkpoint.js +125 -0
  132. package/dist/tools/checkpoint.js.map +1 -0
  133. package/dist/tools/index.d.ts +412 -0
  134. package/dist/tools/index.d.ts.map +1 -0
  135. package/dist/tools/index.js +262 -0
  136. package/dist/tools/index.js.map +1 -0
  137. package/dist/tools/insight.d.ts +65 -0
  138. package/dist/tools/insight.d.ts.map +1 -0
  139. package/dist/tools/insight.js +190 -0
  140. package/dist/tools/insight.js.map +1 -0
  141. package/dist/tools/journey.d.ts +45 -0
  142. package/dist/tools/journey.d.ts.map +1 -0
  143. package/dist/tools/journey.js +115 -0
  144. package/dist/tools/journey.js.map +1 -0
  145. package/dist/tools/sendMessage.d.ts +6 -0
  146. package/dist/tools/sendMessage.d.ts.map +1 -0
  147. package/dist/tools/sendMessage.js +278 -0
  148. package/dist/tools/sendMessage.js.map +1 -0
  149. package/dist/tools/session.d.ts +106 -0
  150. package/dist/tools/session.d.ts.map +1 -0
  151. package/dist/tools/session.js +161 -0
  152. package/dist/tools/session.js.map +1 -0
  153. package/dist/types/auth.d.ts +37 -0
  154. package/dist/types/auth.d.ts.map +1 -0
  155. package/dist/types/auth.js +44 -0
  156. package/dist/types/auth.js.map +1 -0
  157. package/dist/types/checkpoint.d.ts +25 -0
  158. package/dist/types/checkpoint.d.ts.map +1 -0
  159. package/dist/types/checkpoint.js +8 -0
  160. package/dist/types/checkpoint.js.map +1 -0
  161. package/dist/types/insight.d.ts +83 -0
  162. package/dist/types/insight.d.ts.map +1 -0
  163. package/dist/types/insight.js +14 -0
  164. package/dist/types/insight.js.map +1 -0
  165. package/dist/types/journey.d.ts +155 -0
  166. package/dist/types/journey.d.ts.map +1 -0
  167. package/dist/types/journey.js +29 -0
  168. package/dist/types/journey.js.map +1 -0
  169. package/dist/types/session.d.ts +82 -0
  170. package/dist/types/session.d.ts.map +1 -0
  171. package/dist/types/session.js +13 -0
  172. package/dist/types/session.js.map +1 -0
  173. package/dist/utils/circuitBreaker.d.ts +86 -0
  174. package/dist/utils/circuitBreaker.d.ts.map +1 -0
  175. package/dist/utils/circuitBreaker.js +234 -0
  176. package/dist/utils/circuitBreaker.js.map +1 -0
  177. package/dist/utils/errorHandler.d.ts +101 -0
  178. package/dist/utils/errorHandler.d.ts.map +1 -0
  179. package/dist/utils/errorHandler.js +348 -0
  180. package/dist/utils/errorHandler.js.map +1 -0
  181. package/dist/utils/errors.d.ts +36 -0
  182. package/dist/utils/errors.d.ts.map +1 -0
  183. package/dist/utils/errors.js +77 -0
  184. package/dist/utils/errors.js.map +1 -0
  185. package/dist/utils/logger.d.ts +13 -0
  186. package/dist/utils/logger.d.ts.map +1 -0
  187. package/dist/utils/logger.js +49 -0
  188. package/dist/utils/logger.js.map +1 -0
  189. package/dist/utils/performanceMonitor.d.ts +106 -0
  190. package/dist/utils/performanceMonitor.d.ts.map +1 -0
  191. package/dist/utils/performanceMonitor.js +312 -0
  192. package/dist/utils/performanceMonitor.js.map +1 -0
  193. package/dist/utils/responseCache.d.ts +88 -0
  194. package/dist/utils/responseCache.d.ts.map +1 -0
  195. package/dist/utils/responseCache.js +245 -0
  196. package/dist/utils/responseCache.js.map +1 -0
  197. package/dist/utils/retryStrategy.d.ts +49 -0
  198. package/dist/utils/retryStrategy.d.ts.map +1 -0
  199. package/dist/utils/retryStrategy.js +167 -0
  200. package/dist/utils/retryStrategy.js.map +1 -0
  201. package/dist/workflows/definitions/daily-reflection.d.ts +3 -0
  202. package/dist/workflows/definitions/daily-reflection.d.ts.map +1 -0
  203. package/dist/workflows/definitions/daily-reflection.js +52 -0
  204. package/dist/workflows/definitions/daily-reflection.js.map +1 -0
  205. package/dist/workflows/definitions/gratitude-practice.d.ts +3 -0
  206. package/dist/workflows/definitions/gratitude-practice.d.ts.map +1 -0
  207. package/dist/workflows/definitions/gratitude-practice.js +52 -0
  208. package/dist/workflows/definitions/gratitude-practice.js.map +1 -0
  209. package/dist/workflows/definitions/weekly-review.d.ts +3 -0
  210. package/dist/workflows/definitions/weekly-review.d.ts.map +1 -0
  211. package/dist/workflows/definitions/weekly-review.js +74 -0
  212. package/dist/workflows/definitions/weekly-review.js.map +1 -0
  213. package/dist/workflows/engine.d.ts +21 -0
  214. package/dist/workflows/engine.d.ts.map +1 -0
  215. package/dist/workflows/engine.js +149 -0
  216. package/dist/workflows/engine.js.map +1 -0
  217. package/dist/workflows/index.d.ts +26 -0
  218. package/dist/workflows/index.d.ts.map +1 -0
  219. package/dist/workflows/index.js +14 -0
  220. package/dist/workflows/index.js.map +1 -0
  221. package/package.json +98 -0
  222. package/run-mcp-server.sh +16 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Greg Wisenberg
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,358 @@
1
+ # CouchLoop MCP Server
2
+
3
+ Turn conversations into guided journeys that remember where you left off.
4
+
5
+ ## Overview
6
+
7
+ CouchLoop MCP Server provides stateful, resumable conversation experiences for AI agents. It manages sessions, progress checkpoints, and guided journeys - enabling multi-turn experiences that survive interruptions and span multiple conversations.
8
+
9
+ ### What This Is
10
+ - State management infrastructure for AI conversations
11
+ - Journey/workflow orchestration layer
12
+ - Session persistence and resumption
13
+ - MCP (Model Context Protocol) server for ChatGPT and Claude
14
+
15
+ ### What This Is NOT
16
+ - A chatbot or conversational AI
17
+ - A therapy/clinical tool (no PHI)
18
+ - A UI layer (headless, works behind existing chat interfaces)
19
+
20
+ ## Features
21
+
22
+ - **7 MCP Tools** for session management, checkpoints, journeys, and insights
23
+ - **5 MCP Resources** for read-only context access
24
+ - **3 Pre-built Journeys**: Daily Reflection, Gratitude Practice, Weekly Review
25
+ - **Stateful Sessions** that can be paused and resumed
26
+ - **Progress Tracking** with checkpoints and step advancement
27
+ - **User Context** management with preferences and history
28
+ - **OAuth 2.0** authentication for ChatGPT App Store
29
+
30
+ ## Quick Start
31
+
32
+ ### Prerequisites
33
+
34
+ - Node.js 18+
35
+ - PostgreSQL database (via Supabase)
36
+ - npm or yarn
37
+
38
+ ### Installation
39
+
40
+ 1. Clone the repository:
41
+ ```bash
42
+ git clone https://github.com/wisenbergg/couchloop-mcp.git
43
+ cd couchloop-mcp
44
+ ```
45
+
46
+ 2. Install dependencies:
47
+ ```bash
48
+ npm install
49
+ ```
50
+
51
+ 3. Set up environment variables:
52
+ ```bash
53
+ cp .env.example .env
54
+ ```
55
+
56
+ Edit `.env` with your configuration:
57
+
58
+ ### Supabase Setup
59
+
60
+ 1. Create a new project at [supabase.com](https://supabase.com)
61
+ 2. Get your credentials from Project Settings > API:
62
+ - `SUPABASE_URL`: Your project URL
63
+ - `SUPABASE_ANON_KEY`: Your anon/public key
64
+ - `SUPABASE_SERVICE_ROLE_KEY`: Your service role key
65
+ 3. Get database URL from Project Settings > Database:
66
+ - `DATABASE_URL`: Your PostgreSQL connection string
67
+
68
+ ### Environment Configuration
69
+
70
+ ```env
71
+ # Database (Supabase)
72
+ DATABASE_URL=postgresql://postgres:[password]@db.[project].supabase.co:5432/postgres
73
+ SUPABASE_URL=https://[project].supabase.co
74
+ SUPABASE_ANON_KEY=your-anon-key
75
+ SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
76
+
77
+ # OAuth (for ChatGPT App Store)
78
+ OAUTH_CLIENT_ID=couchloop_chatgpt
79
+ OAUTH_CLIENT_SECRET=generate-a-secure-secret
80
+ OAUTH_REDIRECT_URI=https://chat.openai.com/aip/plugin/oauth/callback
81
+ JWT_SECRET=minimum-32-character-secret-key-here
82
+
83
+ # Server
84
+ PORT=3000
85
+ NODE_ENV=development
86
+ LOG_LEVEL=info
87
+ ```
88
+
89
+ ### Database Setup
90
+
91
+ 1. Push schema to database:
92
+ ```bash
93
+ npm run db:push
94
+ ```
95
+
96
+ 2. Seed journey definitions:
97
+ ```bash
98
+ npm run db:seed
99
+ ```
100
+
101
+ 3. (Optional) Open Drizzle Studio to view data:
102
+ ```bash
103
+ npm run db:studio
104
+ ```
105
+
106
+ ### Running the Server
107
+
108
+ #### Development Mode
109
+ ```bash
110
+ npm run dev
111
+ ```
112
+
113
+ #### Production Mode
114
+ ```bash
115
+ npm run build
116
+ npm start
117
+ ```
118
+
119
+ ## MCP Tools
120
+
121
+ ### Session Management
122
+
123
+ #### `create_session`
124
+ Start a new guided session, optionally with a journey.
125
+
126
+ ```json
127
+ {
128
+ "journey_slug": "daily-reflection",
129
+ "context": "Evening check-in"
130
+ }
131
+ ```
132
+
133
+ #### `resume_session`
134
+ Resume a previously paused session.
135
+
136
+ ```json
137
+ {
138
+ "session_id": "uuid-here"
139
+ }
140
+ ```
141
+
142
+ ### Progress Tracking
143
+
144
+ #### `save_checkpoint`
145
+ Save progress or capture a key moment.
146
+
147
+ ```json
148
+ {
149
+ "session_id": "uuid-here",
150
+ "key": "mood",
151
+ "value": "calm and reflective",
152
+ "advance_step": true
153
+ }
154
+ ```
155
+
156
+ #### `get_journey_status`
157
+ Get current progress in a session/journey.
158
+
159
+ ```json
160
+ {
161
+ "session_id": "uuid-here"
162
+ }
163
+ ```
164
+
165
+ ### Journeys
166
+
167
+ #### `list_journeys`
168
+ List available guided journeys.
169
+
170
+ ```json
171
+ {
172
+ "tag": "reflection"
173
+ }
174
+ ```
175
+
176
+ ### Insights
177
+
178
+ #### `save_insight`
179
+ Capture a meaningful insight from the conversation.
180
+
181
+ ```json
182
+ {
183
+ "content": "I notice I'm more energized in the mornings",
184
+ "session_id": "uuid-here",
185
+ "tags": ["self-awareness", "energy"]
186
+ }
187
+ ```
188
+
189
+ #### `get_user_context`
190
+ Get relevant context about the user for personalization.
191
+
192
+ ```json
193
+ {
194
+ "include_recent_insights": true,
195
+ "include_session_history": true
196
+ }
197
+ ```
198
+
199
+ ## MCP Resources
200
+
201
+ - `session://current` - Current active session state
202
+ - `journey://daily-reflection` - Daily Reflection journey definition
203
+ - `journey://gratitude-practice` - Gratitude Practice journey definition
204
+ - `journey://weekly-review` - Weekly Review journey definition
205
+ - `context://user` - User preferences and recent history
206
+
207
+ ## Available Journeys
208
+
209
+ ### Daily Reflection (5 minutes)
210
+ A brief check-in to process your day and capture key moments.
211
+ - Check in with current mood
212
+ - Identify memorable moment
213
+ - Release what's not needed
214
+ - Summarize and save insights
215
+
216
+ ### Gratitude Practice (3 minutes)
217
+ Notice and name three things you appreciate.
218
+ - Something small that made today better
219
+ - Something about yourself you're grateful for
220
+ - Someone you appreciate
221
+
222
+ ### Weekly Review (10 minutes)
223
+ Look back on your week and set intentions.
224
+ - Describe the week's tone
225
+ - Acknowledge accomplishments
226
+ - Notice challenges
227
+ - Set intention for next week
228
+
229
+ ## Development
230
+
231
+ ### Scripts
232
+
233
+ ```bash
234
+ # Development with hot reload
235
+ npm run dev
236
+
237
+ # Build TypeScript
238
+ npm run build
239
+
240
+ # Run tests
241
+ npm test
242
+
243
+ # Type checking
244
+ npm run typecheck
245
+
246
+ # Linting
247
+ npm run lint
248
+
249
+ # Database operations
250
+ npm run db:push # Push schema to database
251
+ npm run db:seed # Seed journeys
252
+ npm run db:studio # Open Drizzle Studio
253
+ npm run db:migrate # Run migrations
254
+
255
+ # Setup helpers
256
+ npm run setup # Install deps and build
257
+ npm run setup:db # Initialize database
258
+ ```
259
+
260
+ ### Project Structure
261
+
262
+ ```
263
+ src/
264
+ ├── index.ts # MCP server entrypoint
265
+ ├── tools/ # MCP tool implementations
266
+ ├── resources/ # MCP resource handlers
267
+ ├── workflows/ # Journey definitions and engine
268
+ ├── db/ # Database schema and client
269
+ ├── auth/ # OAuth 2.0 implementation
270
+ ├── types/ # TypeScript type definitions
271
+ └── utils/ # Logging and error handling
272
+ api/
273
+ └── oauth/ # OAuth endpoints for Vercel
274
+ ├── authorize.ts # Authorization endpoint
275
+ └── token.ts # Token exchange endpoint
276
+ ```
277
+
278
+ ## Deployment
279
+
280
+ ### Vercel Deployment
281
+
282
+ 1. Install Vercel CLI:
283
+ ```bash
284
+ npm install -g vercel
285
+ ```
286
+
287
+ 2. Set up environment variables:
288
+ ```bash
289
+ vercel env add DATABASE_URL
290
+ vercel env add SUPABASE_URL
291
+ vercel env add SUPABASE_ANON_KEY
292
+ vercel env add SUPABASE_SERVICE_ROLE_KEY
293
+ vercel env add OAUTH_CLIENT_ID
294
+ vercel env add OAUTH_CLIENT_SECRET
295
+ vercel env add OAUTH_REDIRECT_URI
296
+ vercel env add JWT_SECRET
297
+ ```
298
+
299
+ 3. Deploy to Vercel:
300
+ ```bash
301
+ # Deploy to preview
302
+ npm run vercel
303
+
304
+ # Deploy to production
305
+ npm run vercel:prod
306
+ ```
307
+
308
+ 4. Your OAuth endpoints will be available at:
309
+ - `https://your-app.vercel.app/api/oauth/authorize`
310
+ - `https://your-app.vercel.app/api/oauth/token`
311
+
312
+ ### ChatGPT App Store Submission
313
+
314
+ 1. Update OAuth redirect URI in `.env` to match ChatGPT's callback
315
+ 2. Ensure all OAuth endpoints are working
316
+ 3. Create test credentials for reviewers
317
+ 4. Prepare privacy policy at `/docs/PRIVACY_POLICY.md`
318
+ 5. Submit via ChatGPT developer portal with:
319
+ - App name: CouchLoop (or your chosen name)
320
+ - Description: Turn conversations into guided journeys
321
+ - OAuth authorization URL: `https://your-app.vercel.app/api/oauth/authorize`
322
+ - OAuth token URL: `https://your-app.vercel.app/api/oauth/token`
323
+ - Scopes: read, write
324
+
325
+ ## Testing
326
+
327
+ Run the test suite:
328
+
329
+ ```bash
330
+ npm test
331
+ ```
332
+
333
+ Run tests in watch mode:
334
+
335
+ ```bash
336
+ npm run test:watch
337
+ ```
338
+
339
+ ## Contributing
340
+
341
+ Contributions are welcome! Please read our contributing guidelines and submit PRs to the main branch.
342
+
343
+ ## License
344
+
345
+ MIT License - see LICENSE file for details
346
+
347
+ ## Support
348
+
349
+ - GitHub Issues: [Report bugs or request features](https://github.com/wisenbergg/couchloop-mcp/issues)
350
+ - Documentation: [Full API documentation](./docs/API.md)
351
+
352
+ ## Acknowledgments
353
+
354
+ Built with:
355
+ - [Model Context Protocol SDK](https://github.com/anthropics/mcp-sdk)
356
+ - [Supabase](https://supabase.com)
357
+ - [Drizzle ORM](https://orm.drizzle.team)
358
+ - [TypeScript](https://www.typescriptlang.org)
@@ -0,0 +1,12 @@
1
+ # Logo Assets
2
+
3
+ Place your logo files in this directory. Recommended formats:
4
+ - PNG (for transparency support)
5
+ - SVG (for scalability)
6
+ - ICO (for favicon)
7
+
8
+ Suggested filenames:
9
+ - `logo.png` - Main logo
10
+ - `logo.svg` - Vector version
11
+ - `favicon.ico` - Browser favicon
12
+ - `logo-small.png` - Small version for UI elements
@@ -0,0 +1,8 @@
1
+ export interface AuthContext {
2
+ userId: string;
3
+ clientId: string;
4
+ scope: string;
5
+ }
6
+ export declare function validateToken(authHeader?: string): Promise<AuthContext>;
7
+ export declare function extractAuthHeader(args: any): string | undefined;
8
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/auth/middleware.ts"],"names":[],"mappings":"AAqBA,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,aAAa,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAsB7E;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM,GAAG,SAAS,CAoB/D"}
@@ -0,0 +1,59 @@
1
+ import { jwtVerify } from 'jose';
2
+ import { AuthenticationError } from '../utils/errors.js';
3
+ // Only validate JWT_SECRET when running as web server (not in MCP mode)
4
+ const isMCPMode = process.env.MCP_MODE === 'true';
5
+ let JWT_SECRET;
6
+ if (!isMCPMode) {
7
+ // Ensure JWT_SECRET is properly set for web server mode
8
+ if (!process.env.JWT_SECRET) {
9
+ throw new Error('JWT_SECRET environment variable must be set when not in MCP mode');
10
+ }
11
+ if (process.env.JWT_SECRET.length < 32) {
12
+ throw new Error('JWT_SECRET must be at least 32 characters long');
13
+ }
14
+ JWT_SECRET = new TextEncoder().encode(process.env.JWT_SECRET);
15
+ }
16
+ else {
17
+ // Use a placeholder for MCP mode (JWT not used in MCP)
18
+ JWT_SECRET = new TextEncoder().encode('mcp-mode-placeholder-not-used-for-auth');
19
+ }
20
+ export async function validateToken(authHeader) {
21
+ if (!authHeader) {
22
+ throw new AuthenticationError('No authorization header');
23
+ }
24
+ if (!authHeader.startsWith('Bearer ')) {
25
+ throw new AuthenticationError('Invalid authorization header format');
26
+ }
27
+ const token = authHeader.slice(7); // Remove "Bearer " prefix
28
+ try {
29
+ const { payload } = await jwtVerify(token, JWT_SECRET);
30
+ return {
31
+ userId: payload.sub,
32
+ clientId: payload.client_id,
33
+ scope: payload.scope,
34
+ };
35
+ }
36
+ catch (error) {
37
+ throw new AuthenticationError('Invalid or expired token');
38
+ }
39
+ }
40
+ export function extractAuthHeader(args) {
41
+ // MCP protocol might pass auth in various ways
42
+ // Check common patterns
43
+ if (args?._auth?.authorization) {
44
+ return args._auth.authorization;
45
+ }
46
+ if (args?.authorization) {
47
+ return args.authorization;
48
+ }
49
+ if (args?.headers?.authorization) {
50
+ return args.headers.authorization;
51
+ }
52
+ // In production mode, require authentication
53
+ if (process.env.NODE_ENV === 'production') {
54
+ return undefined;
55
+ }
56
+ // In development, allow unauthenticated requests
57
+ return 'Bearer development-token';
58
+ }
59
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/auth/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEzD,wEAAwE;AACxE,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM,CAAC;AAElD,IAAI,UAAsB,CAAC;AAC3B,IAAI,CAAC,SAAS,EAAE,CAAC;IACf,wDAAwD;IACxD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,kEAAkE,CAAC,CAAC;IACtF,CAAC;IACD,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACpE,CAAC;IACD,UAAU,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;AAChE,CAAC;KAAM,CAAC;IACN,uDAAuD;IACvD,UAAU,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,wCAAwC,CAAC,CAAC;AAClF,CAAC;AAQD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,UAAmB;IACrD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,mBAAmB,CAAC,yBAAyB,CAAC,CAAC;IAC3D,CAAC;IAED,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,mBAAmB,CAAC,qCAAqC,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,0BAA0B;IAE7D,IAAI,CAAC;QACH,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,SAAS,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;QAEvD,OAAO;YACL,MAAM,EAAE,OAAO,CAAC,GAAa;YAC7B,QAAQ,EAAE,OAAO,CAAC,SAAmB;YACrC,KAAK,EAAE,OAAO,CAAC,KAAe;SAC/B,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,mBAAmB,CAAC,0BAA0B,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAS;IACzC,+CAA+C;IAC/C,wBAAwB;IACxB,IAAI,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC;IAClC,CAAC;IACD,IAAI,IAAI,EAAE,aAAa,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IACD,IAAI,IAAI,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC;QACjC,OAAO,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC;IACpC,CAAC;IAED,6CAA6C;IAC7C,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;QAC1C,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,iDAAiD;IACjD,OAAO,0BAA0B,CAAC;AACpC,CAAC"}
@@ -0,0 +1,195 @@
1
+ import { z } from 'zod';
2
+ export declare const ShrinkResponseSchema: z.ZodObject<{
3
+ reply: z.ZodOptional<z.ZodString>;
4
+ response_text: z.ZodOptional<z.ZodString>;
5
+ content: z.ZodOptional<z.ZodString>;
6
+ messageId: z.ZodOptional<z.ZodString>;
7
+ crisisDetected: z.ZodOptional<z.ZodBoolean>;
8
+ crisisLevel: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodString]>>;
9
+ crisis_level: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
10
+ crisisHandled: z.ZodOptional<z.ZodBoolean>;
11
+ crisis_confidence: z.ZodOptional<z.ZodNumber>;
12
+ emotions: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
13
+ therapeuticTechnique: z.ZodOptional<z.ZodString>;
14
+ resources: z.ZodOptional<z.ZodArray<z.ZodObject<{
15
+ type: z.ZodString;
16
+ title: z.ZodString;
17
+ url: z.ZodOptional<z.ZodString>;
18
+ phone: z.ZodOptional<z.ZodString>;
19
+ description: z.ZodOptional<z.ZodString>;
20
+ }, "strip", z.ZodTypeAny, {
21
+ type: string;
22
+ title: string;
23
+ description?: string | undefined;
24
+ url?: string | undefined;
25
+ phone?: string | undefined;
26
+ }, {
27
+ type: string;
28
+ title: string;
29
+ description?: string | undefined;
30
+ url?: string | undefined;
31
+ phone?: string | undefined;
32
+ }>, "many">>;
33
+ escalationPath: z.ZodOptional<z.ZodString>;
34
+ threadId: z.ZodOptional<z.ZodString>;
35
+ meta: z.ZodOptional<z.ZodObject<{
36
+ rag_confidence: z.ZodOptional<z.ZodNumber>;
37
+ emotionalTone: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
38
+ therapeuticElements: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
39
+ }, "strip", z.ZodTypeAny, {
40
+ rag_confidence?: number | undefined;
41
+ emotionalTone?: string[] | undefined;
42
+ therapeuticElements?: string[] | undefined;
43
+ }, {
44
+ rag_confidence?: number | undefined;
45
+ emotionalTone?: string[] | undefined;
46
+ therapeuticElements?: string[] | undefined;
47
+ }>>;
48
+ memory_high_relevance_count: z.ZodOptional<z.ZodNumber>;
49
+ error: z.ZodOptional<z.ZodString>;
50
+ error_type: z.ZodOptional<z.ZodString>;
51
+ message: z.ZodOptional<z.ZodString>;
52
+ }, "strip", z.ZodTypeAny, {
53
+ threadId?: string | undefined;
54
+ content?: string | undefined;
55
+ crisis_level?: string | number | undefined;
56
+ crisisLevel?: string | number | undefined;
57
+ resources?: {
58
+ type: string;
59
+ title: string;
60
+ description?: string | undefined;
61
+ url?: string | undefined;
62
+ phone?: string | undefined;
63
+ }[] | undefined;
64
+ escalationPath?: string | undefined;
65
+ message?: string | undefined;
66
+ error?: string | undefined;
67
+ reply?: string | undefined;
68
+ response_text?: string | undefined;
69
+ messageId?: string | undefined;
70
+ crisisDetected?: boolean | undefined;
71
+ crisisHandled?: boolean | undefined;
72
+ crisis_confidence?: number | undefined;
73
+ emotions?: string[] | undefined;
74
+ therapeuticTechnique?: string | undefined;
75
+ meta?: {
76
+ rag_confidence?: number | undefined;
77
+ emotionalTone?: string[] | undefined;
78
+ therapeuticElements?: string[] | undefined;
79
+ } | undefined;
80
+ memory_high_relevance_count?: number | undefined;
81
+ error_type?: string | undefined;
82
+ }, {
83
+ threadId?: string | undefined;
84
+ content?: string | undefined;
85
+ crisis_level?: string | number | undefined;
86
+ crisisLevel?: string | number | undefined;
87
+ resources?: {
88
+ type: string;
89
+ title: string;
90
+ description?: string | undefined;
91
+ url?: string | undefined;
92
+ phone?: string | undefined;
93
+ }[] | undefined;
94
+ escalationPath?: string | undefined;
95
+ message?: string | undefined;
96
+ error?: string | undefined;
97
+ reply?: string | undefined;
98
+ response_text?: string | undefined;
99
+ messageId?: string | undefined;
100
+ crisisDetected?: boolean | undefined;
101
+ crisisHandled?: boolean | undefined;
102
+ crisis_confidence?: number | undefined;
103
+ emotions?: string[] | undefined;
104
+ therapeuticTechnique?: string | undefined;
105
+ meta?: {
106
+ rag_confidence?: number | undefined;
107
+ emotionalTone?: string[] | undefined;
108
+ therapeuticElements?: string[] | undefined;
109
+ } | undefined;
110
+ memory_high_relevance_count?: number | undefined;
111
+ error_type?: string | undefined;
112
+ }>;
113
+ export declare const ErrorResponseSchema: z.ZodObject<{
114
+ error: z.ZodOptional<z.ZodString>;
115
+ message: z.ZodOptional<z.ZodString>;
116
+ error_type: z.ZodOptional<z.ZodString>;
117
+ code: z.ZodOptional<z.ZodString>;
118
+ details: z.ZodOptional<z.ZodAny>;
119
+ }, "strip", z.ZodTypeAny, {
120
+ code?: string | undefined;
121
+ message?: string | undefined;
122
+ error?: string | undefined;
123
+ error_type?: string | undefined;
124
+ details?: any;
125
+ }, {
126
+ code?: string | undefined;
127
+ message?: string | undefined;
128
+ error?: string | undefined;
129
+ error_type?: string | undefined;
130
+ details?: any;
131
+ }>;
132
+ export type ShrinkResponse = z.infer<typeof ShrinkResponseSchema>;
133
+ export type ErrorResponse = z.infer<typeof ErrorResponseSchema>;
134
+ export declare class ShrinkChatClient {
135
+ private circuitBreaker;
136
+ private retryStrategy;
137
+ constructor();
138
+ /**
139
+ * Detect if a message contains crisis indicators
140
+ */
141
+ private detectCrisisContent;
142
+ private request;
143
+ /**
144
+ * Send a message through the shrink-chat therapeutic stack
145
+ * Note: Threads are created lazily - no need for separate thread creation
146
+ */
147
+ sendMessage(threadId: string, prompt: string, options?: {
148
+ memoryContext?: string;
149
+ enhancedContext?: any;
150
+ history?: Array<{
151
+ role: string;
152
+ content: string;
153
+ }>;
154
+ systemPrompt?: string;
155
+ conversationType?: string;
156
+ idempotencyKey?: string;
157
+ }): Promise<ShrinkResponse>;
158
+ /**
159
+ * Stream a message response (SSE)
160
+ */
161
+ streamMessage(prompt: string, threadId: string, options?: {
162
+ memoryContext?: string;
163
+ enhancedContext?: any;
164
+ history?: Array<{
165
+ role: string;
166
+ content: string;
167
+ }>;
168
+ systemPrompt?: string;
169
+ conversationType?: string;
170
+ signal?: AbortSignal;
171
+ }): AsyncGenerator<any>;
172
+ /**
173
+ * Get recent messages for a thread
174
+ */
175
+ getRecentMessages(threadId: string, limit?: number): Promise<any>;
176
+ /**
177
+ * Log a message (for offline/manual logging)
178
+ */
179
+ logMessage(threadId: string, role: 'user' | 'assistant', content: string, idempotencyKey?: string): Promise<any>;
180
+ /**
181
+ * Health check for the shrink-chat API
182
+ */
183
+ healthCheck(): Promise<boolean>;
184
+ /**
185
+ * Generate a new thread ID (client-side)
186
+ * Threads are created lazily server-side when first message is sent
187
+ */
188
+ generateThreadId(): string;
189
+ /**
190
+ * Get circuit breaker status
191
+ */
192
+ getCircuitBreakerStatus(): import("../utils/circuitBreaker.js").CircuitBreakerStatistics;
193
+ }
194
+ export declare function getShrinkChatClient(): ShrinkChatClient;
195
+ //# sourceMappingURL=shrinkChatClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shrinkChatClient.d.ts","sourceRoot":"","sources":["../../src/clients/shrinkChatClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAqBxB,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+B/B,CAAC;AAEH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;EAM9B,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAClE,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,aAAa,CAAgB;;IAYrC;;OAEG;IACH,OAAO,CAAC,mBAAmB;YAiBb,OAAO;IAwDrB;;;OAGG;IACG,WAAW,CACf,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;QACR,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,eAAe,CAAC,EAAE,GAAG,CAAC;QACtB,OAAO,CAAC,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QACnD,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,GACA,OAAO,CAAC,cAAc,CAAC;IAwI1B;;OAEG;IACI,aAAa,CAClB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;QACR,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,eAAe,CAAC,EAAE,GAAG,CAAC;QACtB,OAAO,CAAC,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QACnD,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,MAAM,CAAC,EAAE,WAAW,CAAC;KACtB,GACA,cAAc,CAAC,GAAG,CAAC;IAyDtB;;OAEG;IACG,iBAAiB,CACrB,QAAQ,EAAE,MAAM,EAChB,KAAK,GAAE,MAAW,GACjB,OAAO,CAAC,GAAG,CAAC;IAOf;;OAEG;IACG,UAAU,CACd,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GAAG,WAAW,EAC1B,OAAO,EAAE,MAAM,EACf,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,GAAG,CAAC;IAaf;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IASrC;;;OAGG;IACH,gBAAgB,IAAI,MAAM;IAI1B;;OAEG;IACH,uBAAuB;CAGxB;AAKD,wBAAgB,mBAAmB,IAAI,gBAAgB,CAKtD"}