@prmichaelsen/task-mcp 0.2.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.
- package/.env.example +19 -0
- package/AGENT.md +1165 -0
- package/CHANGELOG.md +72 -0
- package/agent/commands/acp.commit.md +511 -0
- package/agent/commands/acp.init.md +376 -0
- package/agent/commands/acp.package-install.md +347 -0
- package/agent/commands/acp.proceed.md +311 -0
- package/agent/commands/acp.report.md +392 -0
- package/agent/commands/acp.status.md +280 -0
- package/agent/commands/acp.sync.md +323 -0
- package/agent/commands/acp.update.md +301 -0
- package/agent/commands/acp.validate.md +385 -0
- package/agent/commands/acp.version-check-for-updates.md +275 -0
- package/agent/commands/acp.version-check.md +190 -0
- package/agent/commands/acp.version-update.md +288 -0
- package/agent/commands/command.template.md +273 -0
- package/agent/commands/git.commit.md +511 -0
- package/agent/commands/git.init.md +513 -0
- package/agent/design/.gitkeep +0 -0
- package/agent/design/acp-task-execution-requirements.md +555 -0
- package/agent/design/api-dto-design.md +394 -0
- package/agent/design/code-extraction-guide.md +827 -0
- package/agent/design/design.template.md +136 -0
- package/agent/design/requirements.template.md +387 -0
- package/agent/design/rest-api-integration.md +489 -0
- package/agent/design/sdk-export-requirements.md +549 -0
- package/agent/milestones/.gitkeep +0 -0
- package/agent/milestones/milestone-1-{title}.template.md +206 -0
- package/agent/milestones/milestone-2-task-infrastructure.md +232 -0
- package/agent/milestones/milestone-4-autonomous-execution.md +235 -0
- package/agent/patterns/.gitkeep +0 -0
- package/agent/patterns/bootstrap.md +1271 -0
- package/agent/patterns/bootstrap.template.md +1237 -0
- package/agent/patterns/pattern.template.md +364 -0
- package/agent/progress.template.yaml +158 -0
- package/agent/progress.yaml +375 -0
- package/agent/scripts/check-for-updates.sh +88 -0
- package/agent/scripts/install.sh +157 -0
- package/agent/scripts/uninstall.sh +75 -0
- package/agent/scripts/update.sh +139 -0
- package/agent/scripts/version.sh +35 -0
- package/agent/tasks/.gitkeep +0 -0
- package/agent/tasks/task-1-{title}.template.md +225 -0
- package/agent/tasks/task-86-task-data-model-schemas.md +143 -0
- package/agent/tasks/task-87-task-database-service.md +220 -0
- package/agent/tasks/task-88-firebase-client-wrapper.md +139 -0
- package/agent/tasks/task-88-task-execution-engine.md +277 -0
- package/agent/tasks/task-89-mcp-server-implementation.md +197 -0
- package/agent/tasks/task-90-build-configuration.md +146 -0
- package/agent/tasks/task-91-deployment-configuration.md +128 -0
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +191 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +191 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov-report/src/client.ts.html +1030 -0
- package/coverage/lcov-report/src/constant/collections.ts.html +469 -0
- package/coverage/lcov-report/src/constant/index.html +116 -0
- package/coverage/lcov-report/src/dto/index.html +116 -0
- package/coverage/lcov-report/src/dto/transformers.ts.html +568 -0
- package/coverage/lcov-report/src/index.html +146 -0
- package/coverage/lcov-report/src/schemas/index.html +116 -0
- package/coverage/lcov-report/src/schemas/task.ts.html +547 -0
- package/coverage/lcov-report/src/server-factory.ts.html +418 -0
- package/coverage/lcov-report/src/server.ts.html +289 -0
- package/coverage/lcov-report/src/services/index.html +116 -0
- package/coverage/lcov-report/src/services/task-database.service.ts.html +1495 -0
- package/coverage/lcov-report/src/tools/index.html +236 -0
- package/coverage/lcov-report/src/tools/index.ts.html +292 -0
- package/coverage/lcov-report/src/tools/task-add-message.ts.html +277 -0
- package/coverage/lcov-report/src/tools/task-complete-task-item.ts.html +343 -0
- package/coverage/lcov-report/src/tools/task-create-milestone.ts.html +286 -0
- package/coverage/lcov-report/src/tools/task-create-task-item.ts.html +358 -0
- package/coverage/lcov-report/src/tools/task-get-next-step.ts.html +460 -0
- package/coverage/lcov-report/src/tools/task-get-status.ts.html +316 -0
- package/coverage/lcov-report/src/tools/task-report-completion.ts.html +343 -0
- package/coverage/lcov-report/src/tools/task-update-progress.ts.html +232 -0
- package/coverage/lcov.info +974 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/coverage/src/client.ts.html +1030 -0
- package/coverage/src/constant/collections.ts.html +469 -0
- package/coverage/src/constant/index.html +116 -0
- package/coverage/src/dto/index.html +116 -0
- package/coverage/src/dto/transformers.ts.html +568 -0
- package/coverage/src/index.html +146 -0
- package/coverage/src/schemas/index.html +116 -0
- package/coverage/src/schemas/task.ts.html +547 -0
- package/coverage/src/server-factory.ts.html +418 -0
- package/coverage/src/server.ts.html +289 -0
- package/coverage/src/services/index.html +116 -0
- package/coverage/src/services/task-database.service.ts.html +1495 -0
- package/coverage/src/tools/index.html +236 -0
- package/coverage/src/tools/index.ts.html +292 -0
- package/coverage/src/tools/task-add-message.ts.html +277 -0
- package/coverage/src/tools/task-complete-task-item.ts.html +343 -0
- package/coverage/src/tools/task-create-milestone.ts.html +286 -0
- package/coverage/src/tools/task-create-task-item.ts.html +358 -0
- package/coverage/src/tools/task-get-next-step.ts.html +460 -0
- package/coverage/src/tools/task-get-status.ts.html +316 -0
- package/coverage/src/tools/task-report-completion.ts.html +343 -0
- package/coverage/src/tools/task-update-progress.ts.html +232 -0
- package/firestore.rules +95 -0
- package/jest.config.js +31 -0
- package/package.json +67 -0
- package/src/client.spec.ts +199 -0
- package/src/client.ts +315 -0
- package/src/constant/collections.ts +128 -0
- package/src/dto/index.ts +47 -0
- package/src/dto/task-api.dto.ts +219 -0
- package/src/dto/transformers.spec.ts +462 -0
- package/src/dto/transformers.ts +161 -0
- package/src/schemas/task.ts +154 -0
- package/src/server-factory.spec.ts +70 -0
- package/src/server-factory.ts +111 -0
- package/src/server.ts +68 -0
- package/src/services/task-database.service.e2e.ts +116 -0
- package/src/services/task-database.service.spec.ts +479 -0
- package/src/services/task-database.service.ts +470 -0
- package/src/test-schemas.ts +161 -0
- package/src/tools/index.ts +69 -0
- package/src/tools/task-add-message.ts +64 -0
- package/src/tools/task-complete-task-item.ts +86 -0
- package/src/tools/task-create-milestone.ts +67 -0
- package/src/tools/task-create-task-item.ts +91 -0
- package/src/tools/task-get-next-step.spec.ts +136 -0
- package/src/tools/task-get-next-step.ts +125 -0
- package/src/tools/task-get-status.spec.ts +213 -0
- package/src/tools/task-get-status.ts +77 -0
- package/src/tools/task-report-completion.ts +86 -0
- package/src/tools/task-update-progress.ts +49 -0
- package/src/tools/tools.spec.ts +194 -0
- package/tsconfig.json +31 -0
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
# REST API Integration Design
|
|
2
|
+
|
|
3
|
+
**Concept**: Deploy separate REST API service alongside MCP server, both accessing same Firestore
|
|
4
|
+
**Created**: 2026-02-16
|
|
5
|
+
**Updated**: 2026-02-16
|
|
6
|
+
**Status**: Design Specification
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
This document specifies the architecture for deploying TWO separate Cloud Run services that share the same codebase and Firestore database:
|
|
13
|
+
|
|
14
|
+
1. **task-mcp-mcp**: MCP protocol server (for AI agents)
|
|
15
|
+
2. **task-mcp-api**: REST API server (for agentbase.me UI)
|
|
16
|
+
|
|
17
|
+
Both services use the same FirebaseClient, TaskDatabaseService, and schemas, but have different entry points and protocols.
|
|
18
|
+
|
|
19
|
+
**Core Principle**: Separate services, shared business logic. No code duplication.
|
|
20
|
+
|
|
21
|
+
**Why Separate Services**:
|
|
22
|
+
- mcp-auth only supports stdio transport currently
|
|
23
|
+
- Different protocols (MCP vs REST)
|
|
24
|
+
- Independent scaling and deployment
|
|
25
|
+
- Clear separation of concerns
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Architecture Pattern
|
|
30
|
+
|
|
31
|
+
### Two-Service Architecture
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
┌──────────────────────────────────────────────────────┐
|
|
35
|
+
│ agentbase.me │
|
|
36
|
+
│ │
|
|
37
|
+
│ ┌──────────────┐ ┌──────────────┐ │
|
|
38
|
+
│ │ Web UI │ │ AI Agent │ │
|
|
39
|
+
│ └──────┬───────┘ └──────┬───────┘ │
|
|
40
|
+
│ │ │ │
|
|
41
|
+
│ │ HTTP REST │ MCP Protocol │
|
|
42
|
+
└─────────┼────────────────────────┼──────────────────┘
|
|
43
|
+
│ │
|
|
44
|
+
▼ ▼
|
|
45
|
+
┌──────────────┐ ┌──────────────┐
|
|
46
|
+
│ task-mcp-api │ │ task-mcp-mcp │
|
|
47
|
+
│ (Cloud Run) │ │ (Cloud Run) │
|
|
48
|
+
│ │ │ │
|
|
49
|
+
│ Fastify │ │ MCP SDK + │
|
|
50
|
+
│ REST API │ │ mcp-auth │
|
|
51
|
+
└──────┬───────┘ └──────┬───────┘
|
|
52
|
+
│ │
|
|
53
|
+
└────────┬───────────────┘
|
|
54
|
+
│
|
|
55
|
+
▼
|
|
56
|
+
┌──────────────────────────────────┐
|
|
57
|
+
│ Shared Business Logic │
|
|
58
|
+
│ (same codebase, different entry)│
|
|
59
|
+
│ │
|
|
60
|
+
│ ┌────────────────────────────┐ │
|
|
61
|
+
│ │ FirebaseClient │ │
|
|
62
|
+
│ │ TaskDatabaseService │ │
|
|
63
|
+
│ │ Schemas │ │
|
|
64
|
+
│ │ Tool Handlers │ │
|
|
65
|
+
│ └────────────────────────────┘ │
|
|
66
|
+
└──────────────────────────────────┘
|
|
67
|
+
│
|
|
68
|
+
▼
|
|
69
|
+
┌──────────────┐
|
|
70
|
+
│ Firestore │
|
|
71
|
+
│ (Single DB) │
|
|
72
|
+
└──────────────┘
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Key Design Decisions
|
|
76
|
+
|
|
77
|
+
1. **Separate Services**: Two Cloud Run deployments (task-mcp-mcp + task-mcp-api)
|
|
78
|
+
2. **Shared Codebase**: Same repo, different entry points (server.ts vs api.ts)
|
|
79
|
+
3. **Shared Database**: Both services access same Firestore database
|
|
80
|
+
4. **Shared Business Logic**: Both use FirebaseClient and TaskDatabaseService
|
|
81
|
+
5. **Different Protocols**: MCP protocol for agents, REST for UI
|
|
82
|
+
6. **User-Scoped**: All operations scoped to `userId` for multi-tenancy
|
|
83
|
+
7. **No 1:1 Mapping**: REST endpoints NOT 1:1 mappings of MCP tools
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## REST API Endpoints
|
|
88
|
+
|
|
89
|
+
### Task Management
|
|
90
|
+
|
|
91
|
+
**Base Path**: `/api/tasks`
|
|
92
|
+
|
|
93
|
+
#### 1. List Tasks
|
|
94
|
+
```
|
|
95
|
+
GET /api/tasks
|
|
96
|
+
Query Parameters:
|
|
97
|
+
- status?: 'not_started' | 'in_progress' | 'paused' | 'completed' | 'failed'
|
|
98
|
+
- limit?: number (default: 50)
|
|
99
|
+
- search?: string
|
|
100
|
+
|
|
101
|
+
Response: Task[]
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
#### 2. Get Task
|
|
105
|
+
```
|
|
106
|
+
GET /api/tasks/:taskId
|
|
107
|
+
|
|
108
|
+
Response: Task
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
#### 3. Create Task
|
|
112
|
+
```
|
|
113
|
+
POST /api/tasks
|
|
114
|
+
Body: {
|
|
115
|
+
title: string
|
|
116
|
+
description: string
|
|
117
|
+
config?: Partial<TaskConfig>
|
|
118
|
+
metadata?: TaskMetadata
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
Response: Task
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
#### 4. Update Task Status
|
|
125
|
+
```
|
|
126
|
+
PATCH /api/tasks/:taskId/status
|
|
127
|
+
Body: {
|
|
128
|
+
status: 'not_started' | 'in_progress' | 'paused' | 'completed' | 'failed'
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
Response: { success: boolean }
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
#### 5. Delete Task
|
|
135
|
+
```
|
|
136
|
+
DELETE /api/tasks/:taskId
|
|
137
|
+
|
|
138
|
+
Response: { success: boolean }
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Progress Management
|
|
142
|
+
|
|
143
|
+
#### 6. Update Progress
|
|
144
|
+
```
|
|
145
|
+
PATCH /api/tasks/:taskId/progress
|
|
146
|
+
Body: {
|
|
147
|
+
percentage: number
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
Response: { success: boolean, progress: number }
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
#### 7. Get Task Messages
|
|
154
|
+
```
|
|
155
|
+
GET /api/tasks/:taskId/messages
|
|
156
|
+
Query Parameters:
|
|
157
|
+
- limit?: number (default: 100)
|
|
158
|
+
|
|
159
|
+
Response: TaskMessage[]
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
#### 8. Add Message
|
|
163
|
+
```
|
|
164
|
+
POST /api/tasks/:taskId/messages
|
|
165
|
+
Body: {
|
|
166
|
+
role: 'user' | 'assistant' | 'system'
|
|
167
|
+
content: string
|
|
168
|
+
metadata?: any
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
Response: { message_id: string }
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Milestone Management
|
|
175
|
+
|
|
176
|
+
#### 9. Create Milestone
|
|
177
|
+
```
|
|
178
|
+
POST /api/tasks/:taskId/milestones
|
|
179
|
+
Body: {
|
|
180
|
+
milestone_id: string
|
|
181
|
+
name: string
|
|
182
|
+
description: string
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
Response: { success: boolean, milestone: Milestone }
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
#### 10. Update Milestone
|
|
189
|
+
```
|
|
190
|
+
PATCH /api/tasks/:taskId/milestones/:milestoneId
|
|
191
|
+
Body: Partial<Milestone>
|
|
192
|
+
|
|
193
|
+
Response: { success: boolean }
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Task Item Management
|
|
197
|
+
|
|
198
|
+
#### 11. Create Task Item
|
|
199
|
+
```
|
|
200
|
+
POST /api/tasks/:taskId/milestones/:milestoneId/items
|
|
201
|
+
Body: {
|
|
202
|
+
task_item_id: string
|
|
203
|
+
name: string
|
|
204
|
+
description: string
|
|
205
|
+
estimated_hours?: number
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
Response: { success: boolean, task_item: TaskItem }
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
#### 12. Complete Task Item
|
|
212
|
+
```
|
|
213
|
+
POST /api/tasks/:taskId/milestones/:milestoneId/items/:taskItemId/complete
|
|
214
|
+
|
|
215
|
+
Response: {
|
|
216
|
+
success: boolean
|
|
217
|
+
milestone_progress: number
|
|
218
|
+
next_task: TaskItem | null
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Implementation Example
|
|
225
|
+
|
|
226
|
+
### REST API Handler (agentbase.me)
|
|
227
|
+
|
|
228
|
+
**Option 1: Using TaskDatabaseService (Recommended for REST API)**
|
|
229
|
+
```typescript
|
|
230
|
+
// In agentbase.me/src/routes/api/tasks/$taskId/index.tsx
|
|
231
|
+
import { TaskDatabaseService } from 'task-mcp/services'
|
|
232
|
+
import { getAuth } from '@/lib/auth/server-fn'
|
|
233
|
+
|
|
234
|
+
export const Route = createAPIFileRoute('/api/tasks/$taskId')({
|
|
235
|
+
GET: async ({ request, params }) => {
|
|
236
|
+
try {
|
|
237
|
+
// Get authenticated user
|
|
238
|
+
const auth = await getAuth(request)
|
|
239
|
+
if (!auth) {
|
|
240
|
+
return new Response(JSON.stringify({ error: 'Unauthorized' }), {
|
|
241
|
+
status: 401,
|
|
242
|
+
headers: { 'Content-Type': 'application/json' }
|
|
243
|
+
})
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Use TaskDatabaseService directly (simpler for REST)
|
|
247
|
+
const task = await TaskDatabaseService.getTask(auth.uid, params.taskId)
|
|
248
|
+
|
|
249
|
+
if (!task) {
|
|
250
|
+
return new Response(JSON.stringify({ error: 'Task not found' }), {
|
|
251
|
+
status: 404,
|
|
252
|
+
headers: { 'Content-Type': 'application/json' }
|
|
253
|
+
})
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return new Response(JSON.stringify({ task }), {
|
|
257
|
+
status: 200,
|
|
258
|
+
headers: { 'Content-Type': 'application/json' }
|
|
259
|
+
})
|
|
260
|
+
} catch (error) {
|
|
261
|
+
return new Response(JSON.stringify({
|
|
262
|
+
error: 'Internal server error',
|
|
263
|
+
message: error instanceof Error ? error.message : 'Unknown error'
|
|
264
|
+
}), {
|
|
265
|
+
status: 500,
|
|
266
|
+
headers: { 'Content-Type': 'application/json' }
|
|
267
|
+
})
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
})
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
**Option 2: Using FirebaseClient (For Connection Management)**
|
|
274
|
+
```typescript
|
|
275
|
+
// In agentbase.me - Alternative approach with client wrapper
|
|
276
|
+
import { FirebaseClient } from 'task-mcp/client'
|
|
277
|
+
import { getAuth } from '@/lib/auth/server-fn'
|
|
278
|
+
|
|
279
|
+
export const Route = createAPIFileRoute('/api/tasks/$taskId')({
|
|
280
|
+
GET: async ({ request, params }) => {
|
|
281
|
+
const auth = await getAuth(request)
|
|
282
|
+
if (!auth) {
|
|
283
|
+
return new Response(JSON.stringify({ error: 'Unauthorized' }), { status: 401 })
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Create client instance (manages connection)
|
|
287
|
+
const client = new FirebaseClient({
|
|
288
|
+
userId: auth.uid,
|
|
289
|
+
serviceAccountPath: process.env.FIREBASE_SERVICE_ACCOUNT_PATH
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
const task = await client.getTask(params.taskId)
|
|
293
|
+
|
|
294
|
+
return new Response(JSON.stringify({ task }), { status: 200 })
|
|
295
|
+
}
|
|
296
|
+
})
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**Recommendation**: Use **TaskDatabaseService** directly in REST API handlers (Option 1) as it's simpler and matches agentbase.me's existing task documentation (Task 89).
|
|
300
|
+
|
|
301
|
+
### MCP Tool Handler (task-mcp)
|
|
302
|
+
|
|
303
|
+
```typescript
|
|
304
|
+
// In task-mcp/src/tools/task-get-status.ts
|
|
305
|
+
import { FirebaseClient } from '../client.js'
|
|
306
|
+
|
|
307
|
+
export async function handleTaskGetStatus(
|
|
308
|
+
client: FirebaseClient,
|
|
309
|
+
args: { task_id: string }
|
|
310
|
+
): Promise<string> {
|
|
311
|
+
// Uses same FirebaseClient as REST API
|
|
312
|
+
const task = await client.getTask(args.task_id)
|
|
313
|
+
|
|
314
|
+
if (!task) {
|
|
315
|
+
throw new Error(`Task not found: ${args.task_id}`)
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Returns instructions for agent (different from REST)
|
|
319
|
+
return JSON.stringify({
|
|
320
|
+
task_title: task.title,
|
|
321
|
+
status: task.status,
|
|
322
|
+
current_milestone: /* ... */,
|
|
323
|
+
instructions: /* ... */
|
|
324
|
+
}, null, 2)
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## Key Differences: MCP Tools vs REST Endpoints
|
|
331
|
+
|
|
332
|
+
### MCP Tools (Agent-Centric)
|
|
333
|
+
- **Purpose**: Provide instructions and guidance for AI agents
|
|
334
|
+
- **Response**: JSON with instructions, context, and next steps
|
|
335
|
+
- **Example**: `task_get_next_step` returns "Continue work on: Task 1\n\nDescription: ..."
|
|
336
|
+
- **Workflow**: Designed around agent decision-making
|
|
337
|
+
|
|
338
|
+
### REST Endpoints (UI-Centric)
|
|
339
|
+
- **Purpose**: Provide data for web UI rendering
|
|
340
|
+
- **Response**: JSON with raw data
|
|
341
|
+
- **Example**: `GET /api/tasks/:id` returns complete Task object
|
|
342
|
+
- **Workflow**: Designed around CRUD operations
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## Authentication & Authorization
|
|
347
|
+
|
|
348
|
+
### REST API
|
|
349
|
+
```typescript
|
|
350
|
+
// In agentbase.me
|
|
351
|
+
import { auth } from '@/lib/firebase-auth'
|
|
352
|
+
|
|
353
|
+
export async function GET(request: NextRequest) {
|
|
354
|
+
// Verify Firebase Auth token
|
|
355
|
+
const token = request.headers.get('Authorization')?.replace('Bearer ', '')
|
|
356
|
+
const decodedToken = await auth.verifyIdToken(token)
|
|
357
|
+
const userId = decodedToken.uid
|
|
358
|
+
|
|
359
|
+
// Use userId for scoped operations
|
|
360
|
+
const client = new FirebaseClient({ userId })
|
|
361
|
+
// ...
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### MCP Server
|
|
366
|
+
```typescript
|
|
367
|
+
// In task-mcp
|
|
368
|
+
export function createServer(userId: string, options: ServerOptions) {
|
|
369
|
+
// userId passed from MCP client (agentbase.me)
|
|
370
|
+
const client = new FirebaseClient({ userId })
|
|
371
|
+
// All operations scoped to this user
|
|
372
|
+
}
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
## Security Considerations
|
|
378
|
+
|
|
379
|
+
### Shared Security Model
|
|
380
|
+
1. **User Isolation**: Both MCP and REST enforce user-scoped operations
|
|
381
|
+
2. **Firestore Rules**: Security rules apply to both access paths
|
|
382
|
+
3. **Service Account**: Same service account used by both
|
|
383
|
+
4. **Rate Limiting**: Apply to both MCP and REST endpoints
|
|
384
|
+
|
|
385
|
+
### REST-Specific Security
|
|
386
|
+
```typescript
|
|
387
|
+
// Rate limiting
|
|
388
|
+
import { rateLimit } from '@/lib/rate-limit'
|
|
389
|
+
|
|
390
|
+
export async function POST(request: NextRequest) {
|
|
391
|
+
const userId = await getUserIdFromRequest(request)
|
|
392
|
+
|
|
393
|
+
// Rate limit per user
|
|
394
|
+
const { success } = await rateLimit.check(userId, 'tasks:create')
|
|
395
|
+
if (!success) {
|
|
396
|
+
return NextResponse.json(
|
|
397
|
+
{ error: 'Rate limit exceeded' },
|
|
398
|
+
{ status: 429 }
|
|
399
|
+
)
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// ... proceed with request
|
|
403
|
+
}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
## Benefits of Dual Interface
|
|
409
|
+
|
|
410
|
+
1. **Code Reuse**: Single business logic layer for both interfaces
|
|
411
|
+
2. **Consistency**: Same data model and validation for MCP and REST
|
|
412
|
+
3. **Flexibility**: UI can use REST, agents can use MCP
|
|
413
|
+
4. **Maintainability**: Changes to business logic affect both interfaces
|
|
414
|
+
5. **Testing**: Test business logic once, works for both interfaces
|
|
415
|
+
|
|
416
|
+
---
|
|
417
|
+
|
|
418
|
+
## Anti-Patterns to Avoid
|
|
419
|
+
|
|
420
|
+
### ❌ 1:1 REST-to-MCP Mapping
|
|
421
|
+
```typescript
|
|
422
|
+
// WRONG - Just wrapping REST endpoints as MCP tools
|
|
423
|
+
export const taskGetTool = {
|
|
424
|
+
name: 'task_get',
|
|
425
|
+
// ...
|
|
426
|
+
}
|
|
427
|
+
// This is just GET /api/tasks/:id as an MCP tool
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### ❌ Calling MCP Tools from REST
|
|
431
|
+
```typescript
|
|
432
|
+
// WRONG - Bypassing MCP protocol
|
|
433
|
+
import { handleTaskGetStatus } from 'task-mcp/tools'
|
|
434
|
+
|
|
435
|
+
app.get('/api/tasks/:id/status', async (req, res) => {
|
|
436
|
+
const result = await handleTaskGetStatus(client, { task_id: req.params.id })
|
|
437
|
+
res.json(JSON.parse(result))
|
|
438
|
+
})
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
### ✅ Correct Approach
|
|
442
|
+
```typescript
|
|
443
|
+
// CORRECT - Sharing business logic
|
|
444
|
+
import { FirebaseClient } from 'task-mcp'
|
|
445
|
+
|
|
446
|
+
app.get('/api/tasks/:id', async (req, res) => {
|
|
447
|
+
const client = new FirebaseClient({ userId: req.user.id })
|
|
448
|
+
const task = await client.getTask(req.params.id) // Shared logic
|
|
449
|
+
res.json(task)
|
|
450
|
+
})
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
---
|
|
454
|
+
|
|
455
|
+
## Implementation Phases
|
|
456
|
+
|
|
457
|
+
### Phase 1: MCP Server (Current)
|
|
458
|
+
- ✅ FirebaseClient and TaskDatabaseService
|
|
459
|
+
- ✅ 8 MCP tools for agent workflows
|
|
460
|
+
- 📋 MCP server with stdio transport
|
|
461
|
+
|
|
462
|
+
### Phase 2: REST API (agentbase.me)
|
|
463
|
+
- 📋 REST endpoints using FirebaseClient
|
|
464
|
+
- 📋 Authentication middleware
|
|
465
|
+
- 📋 Rate limiting
|
|
466
|
+
- 📋 OpenAPI documentation
|
|
467
|
+
|
|
468
|
+
### Phase 3: Integration
|
|
469
|
+
- 📋 Deploy both MCP server and REST API
|
|
470
|
+
- 📋 Test dual interface
|
|
471
|
+
- 📋 Monitor performance
|
|
472
|
+
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
## Success Criteria
|
|
476
|
+
|
|
477
|
+
- [ ] REST endpoints use FirebaseClient (shared logic)
|
|
478
|
+
- [ ] No code duplication between MCP and REST
|
|
479
|
+
- [ ] User isolation enforced in both interfaces
|
|
480
|
+
- [ ] REST endpoints documented with OpenAPI
|
|
481
|
+
- [ ] Integration tests for both interfaces
|
|
482
|
+
- [ ] Performance metrics for both paths
|
|
483
|
+
|
|
484
|
+
---
|
|
485
|
+
|
|
486
|
+
**Status**: Design Specification
|
|
487
|
+
**Next Action**: Implement REST endpoints in agentbase.me after MCP server is complete
|
|
488
|
+
**Owner**: Development Team
|
|
489
|
+
**Created**: 2026-02-16
|