mcp-quickbase 2.0.5 → 2.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/.crewchief/runs/state.json +3 -0
- package/.mcp.json +6 -32
- package/.sdd/tickets/RELS_relationship-management/README.md +98 -0
- package/.sdd/tickets/RELS_relationship-management/planning/analysis.md +190 -0
- package/.sdd/tickets/RELS_relationship-management/planning/architecture.md +413 -0
- package/.sdd/tickets/RELS_relationship-management/planning/plan.md +177 -0
- package/.sdd/tickets/RELS_relationship-management/planning/quality-strategy.md +335 -0
- package/.sdd/tickets/RELS_relationship-management/planning/review-updates.md +95 -0
- package/.sdd/tickets/RELS_relationship-management/planning/security-review.md +213 -0
- package/.sdd/tickets/RELS_relationship-management/planning/ticket-review.md +885 -0
- package/.sdd/tickets/RELS_relationship-management/tasks/RELS.1001_domain-setup.md +96 -0
- package/.sdd/tickets/RELS_relationship-management/tasks/RELS.1002_get-relationships-tool.md +142 -0
- package/.sdd/tickets/RELS_relationship-management/tasks/RELS.1003_register-phase1-tools.md +105 -0
- package/.sdd/tickets/RELS_relationship-management/tasks/RELS.2001_create-relationship-tool.md +151 -0
- package/.sdd/tickets/RELS_relationship-management/tasks/RELS.2002_update-relationship-tool.md +145 -0
- package/.sdd/tickets/RELS_relationship-management/tasks/RELS.3001_delete-relationship-tool.md +154 -0
- package/.sdd/tickets/RELS_relationship-management/tasks/RELS.4001_integration-testing.md +159 -0
- package/.sdd/tickets/RELS_relationship-management/tasks/RELS.4002_final-verification.md +182 -0
- package/.sdd/tickets/RELS_relationship-management/tasks/RELS_TASK_INDEX.md +179 -0
- package/crewchief.config.js +31 -0
- package/dist/client/quickbase.d.ts +7 -2
- package/dist/client/quickbase.js +64 -51
- package/dist/client/quickbase.js.map +1 -1
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/server.d.ts +3 -3
- package/dist/mcp/server.js +21 -17
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp-stdio-server.js +64 -49
- package/dist/mcp-stdio-server.js.map +1 -1
- package/dist/server.js +84 -83
- package/dist/server.js.map +1 -1
- package/dist/tools/apps/create_app.d.ts +2 -2
- package/dist/tools/apps/create_app.js +23 -23
- package/dist/tools/apps/create_app.js.map +1 -1
- package/dist/tools/apps/index.d.ts +4 -4
- package/dist/tools/apps/index.js +3 -3
- package/dist/tools/apps/list_tables.d.ts +7 -7
- package/dist/tools/apps/list_tables.js +28 -27
- package/dist/tools/apps/list_tables.js.map +1 -1
- package/dist/tools/apps/update_app.d.ts +2 -2
- package/dist/tools/apps/update_app.js +28 -26
- package/dist/tools/apps/update_app.js.map +1 -1
- package/dist/tools/base.d.ts +3 -3
- package/dist/tools/base.js +7 -7
- package/dist/tools/base.js.map +1 -1
- package/dist/tools/configure_cache.d.ts +3 -3
- package/dist/tools/configure_cache.js +16 -16
- package/dist/tools/configure_cache.js.map +1 -1
- package/dist/tools/fields/create_field.d.ts +8 -7
- package/dist/tools/fields/create_field.js +39 -29
- package/dist/tools/fields/create_field.js.map +1 -1
- package/dist/tools/fields/delete_field.d.ts +79 -0
- package/dist/tools/fields/delete_field.js +105 -0
- package/dist/tools/fields/delete_field.js.map +1 -0
- package/dist/tools/fields/get_field.d.ts +91 -0
- package/dist/tools/fields/get_field.js +82 -0
- package/dist/tools/fields/get_field.js.map +1 -0
- package/dist/tools/fields/index.d.ts +5 -3
- package/dist/tools/fields/index.js +11 -5
- package/dist/tools/fields/index.js.map +1 -1
- package/dist/tools/fields/update_field.d.ts +7 -15
- package/dist/tools/fields/update_field.js +39 -38
- package/dist/tools/fields/update_field.js.map +1 -1
- package/dist/tools/files/download_file.d.ts +2 -2
- package/dist/tools/files/download_file.js +35 -35
- package/dist/tools/files/download_file.js.map +1 -1
- package/dist/tools/files/index.d.ts +3 -3
- package/dist/tools/files/index.js +3 -3
- package/dist/tools/files/upload_file.d.ts +2 -2
- package/dist/tools/files/upload_file.js +52 -44
- package/dist/tools/files/upload_file.js.map +1 -1
- package/dist/tools/index.d.ts +13 -12
- package/dist/tools/index.js +6 -3
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/records/bulk_create_records.d.ts +2 -2
- package/dist/tools/records/bulk_create_records.js +28 -28
- package/dist/tools/records/bulk_create_records.js.map +1 -1
- package/dist/tools/records/bulk_update_records.d.ts +2 -2
- package/dist/tools/records/bulk_update_records.js +27 -27
- package/dist/tools/records/bulk_update_records.js.map +1 -1
- package/dist/tools/records/create_record.d.ts +2 -2
- package/dist/tools/records/create_record.js +40 -40
- package/dist/tools/records/create_record.js.map +1 -1
- package/dist/tools/records/index.d.ts +6 -6
- package/dist/tools/records/index.js +3 -3
- package/dist/tools/records/query_records.d.ts +3 -3
- package/dist/tools/records/query_records.js +82 -78
- package/dist/tools/records/query_records.js.map +1 -1
- package/dist/tools/records/update_record.d.ts +2 -2
- package/dist/tools/records/update_record.js +31 -29
- package/dist/tools/records/update_record.js.map +1 -1
- package/dist/tools/registry.d.ts +1 -1
- package/dist/tools/registry.js +1 -1
- package/dist/tools/relationships/create_relationship.d.ts +150 -0
- package/dist/tools/relationships/create_relationship.js +181 -0
- package/dist/tools/relationships/create_relationship.js.map +1 -0
- package/dist/tools/relationships/delete_relationship.d.ts +66 -0
- package/dist/tools/relationships/delete_relationship.js +85 -0
- package/dist/tools/relationships/delete_relationship.js.map +1 -0
- package/dist/tools/relationships/get_relationships.d.ts +126 -0
- package/dist/tools/relationships/get_relationships.js +126 -0
- package/dist/tools/relationships/get_relationships.js.map +1 -0
- package/dist/tools/relationships/index.d.ts +14 -0
- package/dist/tools/relationships/index.js +37 -0
- package/dist/tools/relationships/index.js.map +1 -0
- package/dist/tools/relationships/update_relationship.d.ts +139 -0
- package/dist/tools/relationships/update_relationship.js +168 -0
- package/dist/tools/relationships/update_relationship.js.map +1 -0
- package/dist/tools/reports/index.d.ts +2 -2
- package/dist/tools/reports/index.js +3 -3
- package/dist/tools/reports/run_report.d.ts +3 -3
- package/dist/tools/reports/run_report.js +29 -29
- package/dist/tools/reports/run_report.js.map +1 -1
- package/dist/tools/tables/create_table.d.ts +2 -49
- package/dist/tools/tables/create_table.js +26 -49
- package/dist/tools/tables/create_table.js.map +1 -1
- package/dist/tools/tables/get_table_fields.d.ts +2 -2
- package/dist/tools/tables/get_table_fields.js +25 -25
- package/dist/tools/tables/get_table_fields.js.map +1 -1
- package/dist/tools/tables/index.d.ts +4 -4
- package/dist/tools/tables/index.js +3 -3
- package/dist/tools/tables/update_table.d.ts +2 -2
- package/dist/tools/tables/update_table.js +28 -26
- package/dist/tools/tables/update_table.js.map +1 -1
- package/dist/tools/test_connection.d.ts +2 -2
- package/dist/tools/test_connection.js +28 -28
- package/dist/tools/test_connection.js.map +1 -1
- package/dist/types/api.d.ts +1 -1
- package/dist/types/mcp.d.ts +1 -1
- package/dist/utils/cache.js +16 -16
- package/dist/utils/cache.js.map +1 -1
- package/dist/utils/file.js +44 -40
- package/dist/utils/file.js.map +1 -1
- package/dist/utils/logger.js +30 -28
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/retry.js +10 -10
- package/dist/utils/retry.js.map +1 -1
- package/dist/utils/validation.d.ts +1 -1
- package/dist/utils/validation.js +39 -36
- package/dist/utils/validation.js.map +1 -1
- package/docs/README.md +6 -0
- package/docs/future-improvements.md +33 -0
- package/docs/migration-guide.md +160 -0
- package/docs/release-notes.md +89 -0
- package/package.json +5 -4
- /package/{HARDENING_SUMMARY.md → docs/hardening-summary.md} +0 -0
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
# Architecture: Relationship Management
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This feature adds a new `relationships` domain to the MCP Quickbase server, following the established patterns used by other domains (apps, tables, fields, etc.). The implementation consists of four tools mapping directly to the Quickbase Relationships API endpoints, with special attention to tool descriptions that clearly communicate destructive behavior to AI agents.
|
|
6
|
+
|
|
7
|
+
## Design Decisions
|
|
8
|
+
|
|
9
|
+
### Decision 1: Separate Relationships Domain
|
|
10
|
+
|
|
11
|
+
**Context:** Relationships could be implemented as part of the `tables` domain or as a new domain.
|
|
12
|
+
|
|
13
|
+
**Decision:** Create a new `src/tools/relationships/` domain directory.
|
|
14
|
+
|
|
15
|
+
**Rationale:**
|
|
16
|
+
- Follows existing pattern where each API resource area has its own domain
|
|
17
|
+
- Provides clear separation of concerns
|
|
18
|
+
- Allows for future expansion (e.g., cross-app relationship tools)
|
|
19
|
+
- Consistent with how `fields`, `records`, `files`, `reports` are organized
|
|
20
|
+
|
|
21
|
+
### Decision 2: Agent-Safety-First Tool Descriptions
|
|
22
|
+
|
|
23
|
+
**Context:** The delete operation is highly destructive, and agents may use tools without fully understanding consequences.
|
|
24
|
+
|
|
25
|
+
**Decision:** Implement a description format that:
|
|
26
|
+
1. Starts with clear action statement
|
|
27
|
+
2. Includes WARNING label for destructive operations
|
|
28
|
+
3. Lists exactly what will be deleted/lost
|
|
29
|
+
4. Suggests safer alternatives where applicable
|
|
30
|
+
5. Recommends user confirmation for destructive operations
|
|
31
|
+
|
|
32
|
+
**Rationale:**
|
|
33
|
+
- MCP tool descriptions are the primary way agents understand tool behavior
|
|
34
|
+
- Explicit warnings reduce risk of unintended data loss
|
|
35
|
+
- Following patterns from other enterprise API tools
|
|
36
|
+
- Aligns with user requirement for "clearly indicate potentially destructive changes"
|
|
37
|
+
|
|
38
|
+
### Decision 3: Flat Parameter Structure
|
|
39
|
+
|
|
40
|
+
**Context:** The API has nested structures for summary fields (accumulationType, where, label).
|
|
41
|
+
|
|
42
|
+
**Decision:** Use flat parameter structures with clear naming:
|
|
43
|
+
```typescript
|
|
44
|
+
{
|
|
45
|
+
summary_field_id: number;
|
|
46
|
+
summary_label: string;
|
|
47
|
+
summary_accumulation_type: string;
|
|
48
|
+
summary_where?: string;
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Rationale:**
|
|
53
|
+
- Matches existing tool patterns (e.g., `create_field`)
|
|
54
|
+
- Simpler for agents to construct
|
|
55
|
+
- Reduces nesting complexity in JSON Schema
|
|
56
|
+
- Clear parameter names are self-documenting
|
|
57
|
+
|
|
58
|
+
### Decision 4: TypeScript Interfaces for API Types
|
|
59
|
+
|
|
60
|
+
**Context:** Need to represent Quickbase API response types.
|
|
61
|
+
|
|
62
|
+
**Decision:** Define interfaces in each tool file for params and results, following existing patterns.
|
|
63
|
+
|
|
64
|
+
**Rationale:**
|
|
65
|
+
- Consistent with existing codebase (see `create_table.ts`, `create_field.ts`)
|
|
66
|
+
- Keeps related types close to their usage
|
|
67
|
+
- Enables strong typing throughout
|
|
68
|
+
|
|
69
|
+
## Technology Choices
|
|
70
|
+
|
|
71
|
+
| Component | Choice | Rationale |
|
|
72
|
+
|-----------|--------|-----------|
|
|
73
|
+
| Language | TypeScript | Existing codebase uses TypeScript with strict mode |
|
|
74
|
+
| Validation | Zod (via base class) | Already integrated in BaseTool |
|
|
75
|
+
| HTTP Client | QuickbaseClient | Existing client with retry, caching, rate limiting |
|
|
76
|
+
| Testing | Jest | Existing test framework |
|
|
77
|
+
| Linting | ESLint + Prettier | Existing configuration |
|
|
78
|
+
|
|
79
|
+
## Component Design
|
|
80
|
+
|
|
81
|
+
### Directory Structure
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
src/tools/relationships/
|
|
85
|
+
index.ts # Domain registration and exports
|
|
86
|
+
get_relationships.ts # GET /relationships tool
|
|
87
|
+
create_relationship.ts # POST /relationships tool
|
|
88
|
+
update_relationship.ts # POST /relationships/{id} tool
|
|
89
|
+
delete_relationship.ts # DELETE /relationships/{id} tool
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Component 1: GetRelationshipsTool
|
|
93
|
+
|
|
94
|
+
**Responsibilities:**
|
|
95
|
+
- Query all relationships for a given table
|
|
96
|
+
- Support pagination (skip parameter)
|
|
97
|
+
- Return relationship metadata including lookup and summary fields
|
|
98
|
+
|
|
99
|
+
**Interface:**
|
|
100
|
+
```typescript
|
|
101
|
+
interface GetRelationshipsParams {
|
|
102
|
+
table_id: string; // Required: Child table ID (DBID)
|
|
103
|
+
skip?: number; // Optional: Pagination offset
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
interface GetRelationshipsResult {
|
|
107
|
+
relationships: Relationship[];
|
|
108
|
+
metadata: {
|
|
109
|
+
totalRelationships: number;
|
|
110
|
+
numRelationships: number;
|
|
111
|
+
skip: number;
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Description Format:**
|
|
117
|
+
```
|
|
118
|
+
Gets all table-to-table relationships for a specified table. Returns both relationships
|
|
119
|
+
where this table is the child (has reference fields pointing to parents) and where this
|
|
120
|
+
table is the parent (has child tables referencing it). Use this tool to explore table
|
|
121
|
+
structure and understand data connections before modifying relationships.
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Component 2: CreateRelationshipTool
|
|
125
|
+
|
|
126
|
+
**Responsibilities:**
|
|
127
|
+
- Create new relationship between tables
|
|
128
|
+
- Optionally create lookup fields during creation
|
|
129
|
+
- Optionally create summary field during creation
|
|
130
|
+
|
|
131
|
+
**Interface:**
|
|
132
|
+
```typescript
|
|
133
|
+
interface CreateRelationshipParams {
|
|
134
|
+
table_id: string; // Required: Child table ID
|
|
135
|
+
parent_table_id: string; // Required: Parent table ID
|
|
136
|
+
foreign_key_label?: string; // Optional: Label for reference field
|
|
137
|
+
lookup_field_ids?: number[]; // Optional: Parent field IDs to create as lookups
|
|
138
|
+
summary_field_id?: number; // Optional: Child field ID to summarize
|
|
139
|
+
summary_label?: string; // Optional: Label for summary field
|
|
140
|
+
summary_accumulation_type?: string; // Required if summary_field_id: SUM/COUNT/AVG/MAX/MIN
|
|
141
|
+
summary_where?: string; // Optional: Quickbase query filter for summary
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Note: JSON Schema validation must enforce that summary_accumulation_type is required
|
|
145
|
+
// when summary_field_id is provided. Use conditional validation in paramSchema.
|
|
146
|
+
|
|
147
|
+
interface CreateRelationshipResult {
|
|
148
|
+
id: number;
|
|
149
|
+
parentTableId: string;
|
|
150
|
+
childTableId: string;
|
|
151
|
+
foreignKeyField: FieldInfo;
|
|
152
|
+
lookupFields: FieldInfo[];
|
|
153
|
+
summaryFields: FieldInfo[];
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Description Format:**
|
|
158
|
+
```
|
|
159
|
+
Creates a new table-to-table relationship linking a child table to a parent table.
|
|
160
|
+
This creates a reference field in the child table. Optionally creates lookup fields
|
|
161
|
+
(to display parent data in child records) and/or a summary field (to aggregate child
|
|
162
|
+
data in parent records). Relationships can only be created between tables in the same
|
|
163
|
+
application. This operation is SAFE and does not modify existing data.
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Component 3: UpdateRelationshipTool
|
|
167
|
+
|
|
168
|
+
**Responsibilities:**
|
|
169
|
+
- Add lookup fields to existing relationship
|
|
170
|
+
- Add summary field to existing relationship
|
|
171
|
+
- Does NOT delete existing fields (additive only)
|
|
172
|
+
|
|
173
|
+
**Interface:**
|
|
174
|
+
```typescript
|
|
175
|
+
interface UpdateRelationshipParams {
|
|
176
|
+
table_id: string; // Required: Child table ID
|
|
177
|
+
relationship_id: number; // Required: Relationship ID (foreign key field ID)
|
|
178
|
+
lookup_field_ids?: number[]; // Optional: Additional parent field IDs for lookups
|
|
179
|
+
summary_field_id?: number; // Optional: Child field ID to summarize
|
|
180
|
+
summary_label?: string; // Optional: Label for summary field
|
|
181
|
+
summary_accumulation_type?: string; // Required if summary_field_id
|
|
182
|
+
summary_where?: string; // Optional: Quickbase query filter
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Note: JSON Schema validation must enforce that summary_accumulation_type is required
|
|
186
|
+
// when summary_field_id is provided. Use conditional validation in paramSchema.
|
|
187
|
+
|
|
188
|
+
interface UpdateRelationshipResult {
|
|
189
|
+
id: number;
|
|
190
|
+
parentTableId: string;
|
|
191
|
+
childTableId: string;
|
|
192
|
+
foreignKeyField: FieldInfo;
|
|
193
|
+
lookupFields: FieldInfo[];
|
|
194
|
+
summaryFields: FieldInfo[];
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
**Description Format:**
|
|
199
|
+
```
|
|
200
|
+
Adds lookup fields and/or summary fields to an existing relationship. This operation
|
|
201
|
+
is ADDITIVE ONLY - it will not delete existing lookup or summary fields. Use this to
|
|
202
|
+
enhance relationships with additional calculated fields. To remove fields from a
|
|
203
|
+
relationship, you must delete them individually using the field deletion tools.
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Component 4: DeleteRelationshipTool
|
|
207
|
+
|
|
208
|
+
**Responsibilities:**
|
|
209
|
+
- Delete entire relationship
|
|
210
|
+
- Clearly warn about data loss in description
|
|
211
|
+
- Return confirmation of what was deleted
|
|
212
|
+
|
|
213
|
+
**Interface:**
|
|
214
|
+
```typescript
|
|
215
|
+
interface DeleteRelationshipParams {
|
|
216
|
+
table_id: string; // Required: Child table ID
|
|
217
|
+
relationship_id: number; // Required: Relationship ID to delete
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
interface DeleteRelationshipResult {
|
|
221
|
+
relationshipId: number;
|
|
222
|
+
deleted: boolean;
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
**Description Format (Critical for Agent Safety):**
|
|
227
|
+
```
|
|
228
|
+
WARNING: DESTRUCTIVE OPERATION - Permanently deletes an entire table-to-table
|
|
229
|
+
relationship INCLUDING ALL LOOKUP AND SUMMARY FIELDS associated with it. All data
|
|
230
|
+
in those fields will be permanently lost and CANNOT be recovered. The reference
|
|
231
|
+
field in the child table will NOT be deleted (it will remain and may need to be
|
|
232
|
+
manually deleted using field deletion tools if no longer needed). Before using
|
|
233
|
+
this tool:
|
|
234
|
+
1. Use get_relationships to see what fields will be deleted
|
|
235
|
+
2. Confirm with the user that they want to proceed
|
|
236
|
+
3. Consider if you only need to delete specific fields instead
|
|
237
|
+
|
|
238
|
+
Only use this tool when you are certain the entire relationship should be removed.
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Shared Types
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
interface FieldInfo {
|
|
245
|
+
id: number;
|
|
246
|
+
label: string;
|
|
247
|
+
type: string;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
interface Relationship {
|
|
251
|
+
id: number;
|
|
252
|
+
parentTableId: string;
|
|
253
|
+
childTableId: string;
|
|
254
|
+
foreignKeyField: FieldInfo;
|
|
255
|
+
isCrossApp: boolean;
|
|
256
|
+
lookupFields: FieldInfo[];
|
|
257
|
+
summaryFields: FieldInfo[];
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## Data Flow
|
|
262
|
+
|
|
263
|
+
### Get Relationships Flow
|
|
264
|
+
|
|
265
|
+
```
|
|
266
|
+
Agent Request
|
|
267
|
+
|
|
|
268
|
+
v
|
|
269
|
+
GetRelationshipsTool.execute(params)
|
|
270
|
+
|
|
|
271
|
+
v
|
|
272
|
+
BaseTool.validateParams(params)
|
|
273
|
+
|
|
|
274
|
+
v
|
|
275
|
+
QuickbaseClient.request({
|
|
276
|
+
method: 'GET',
|
|
277
|
+
path: `/tables/${tableId}/relationships`,
|
|
278
|
+
params: { skip }
|
|
279
|
+
})
|
|
280
|
+
|
|
|
281
|
+
v
|
|
282
|
+
Transform API Response
|
|
283
|
+
|
|
|
284
|
+
v
|
|
285
|
+
Return GetRelationshipsResult
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Create Relationship Flow
|
|
289
|
+
|
|
290
|
+
```
|
|
291
|
+
Agent Request
|
|
292
|
+
|
|
|
293
|
+
v
|
|
294
|
+
CreateRelationshipTool.execute(params)
|
|
295
|
+
|
|
|
296
|
+
v
|
|
297
|
+
BaseTool.validateParams(params)
|
|
298
|
+
|
|
|
299
|
+
v
|
|
300
|
+
Build Request Body (parentTableId, lookupFieldIds, summaryFields)
|
|
301
|
+
|
|
|
302
|
+
v
|
|
303
|
+
QuickbaseClient.request({
|
|
304
|
+
method: 'POST',
|
|
305
|
+
path: `/tables/${tableId}/relationships`,
|
|
306
|
+
body: requestBody
|
|
307
|
+
})
|
|
308
|
+
|
|
|
309
|
+
v
|
|
310
|
+
Transform API Response
|
|
311
|
+
|
|
|
312
|
+
v
|
|
313
|
+
Return CreateRelationshipResult
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### Delete Relationship Flow
|
|
317
|
+
|
|
318
|
+
```
|
|
319
|
+
Agent Request
|
|
320
|
+
|
|
|
321
|
+
v
|
|
322
|
+
DeleteRelationshipTool.execute(params)
|
|
323
|
+
|
|
|
324
|
+
v
|
|
325
|
+
BaseTool.validateParams(params)
|
|
326
|
+
|
|
|
327
|
+
v
|
|
328
|
+
QuickbaseClient.request({
|
|
329
|
+
method: 'DELETE',
|
|
330
|
+
path: `/tables/${tableId}/relationships/${relationshipId}`
|
|
331
|
+
})
|
|
332
|
+
|
|
|
333
|
+
v
|
|
334
|
+
Return DeleteRelationshipResult (confirmation)
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
## Integration Points
|
|
338
|
+
|
|
339
|
+
### Tool Registration
|
|
340
|
+
|
|
341
|
+
Update `src/tools/index.ts`:
|
|
342
|
+
```typescript
|
|
343
|
+
import { registerRelationshipTools } from './relationships';
|
|
344
|
+
|
|
345
|
+
export function initializeTools(client: QuickbaseClient, cacheService: CacheService): void {
|
|
346
|
+
// ... existing registrations ...
|
|
347
|
+
|
|
348
|
+
// Register relationship management tools
|
|
349
|
+
registerRelationshipTools(client);
|
|
350
|
+
|
|
351
|
+
// ...
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
export * from './relationships';
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### API Endpoints
|
|
358
|
+
|
|
359
|
+
All tools use the existing `QuickbaseClient.request()` method with these endpoints:
|
|
360
|
+
|
|
361
|
+
| Tool | Method | Path |
|
|
362
|
+
|------|--------|------|
|
|
363
|
+
| get_relationships | GET | `/tables/{tableId}/relationships` |
|
|
364
|
+
| create_relationship | POST | `/tables/{tableId}/relationships` |
|
|
365
|
+
| update_relationship | POST | `/tables/{tableId}/relationships/{relationshipId}` |
|
|
366
|
+
| delete_relationship | DELETE | `/tables/{tableId}/relationships/{relationshipId}` |
|
|
367
|
+
|
|
368
|
+
### Caching Behavior
|
|
369
|
+
|
|
370
|
+
- GET requests are cached by `QuickbaseClient` by default
|
|
371
|
+
- Create/Update/Delete requests skip cache and may invalidate related cached data
|
|
372
|
+
- Consider adding `skipCache: true` for relationship queries if stale data is problematic
|
|
373
|
+
|
|
374
|
+
## Performance Considerations
|
|
375
|
+
|
|
376
|
+
### Rate Limiting
|
|
377
|
+
|
|
378
|
+
- Existing rate limiter (10 req/sec default) handles all requests
|
|
379
|
+
- Relationship operations are typically low-volume
|
|
380
|
+
- No special performance optimizations needed
|
|
381
|
+
|
|
382
|
+
### Response Size
|
|
383
|
+
|
|
384
|
+
- `get_relationships` may return large responses for tables with many relationships
|
|
385
|
+
- Pagination (skip parameter) is available for large result sets
|
|
386
|
+
- No need for custom pagination handling beyond exposing skip parameter
|
|
387
|
+
|
|
388
|
+
## Maintainability
|
|
389
|
+
|
|
390
|
+
### Code Organization
|
|
391
|
+
|
|
392
|
+
- Each tool in its own file with params/result interfaces
|
|
393
|
+
- Shared types can be extracted to a types file if needed later
|
|
394
|
+
- Registration pattern keeps index.ts clean
|
|
395
|
+
|
|
396
|
+
### Error Handling
|
|
397
|
+
|
|
398
|
+
- Use existing `ApiResponse` pattern with success/error states
|
|
399
|
+
- Throw descriptive errors that bubble up through BaseTool
|
|
400
|
+
- Include table ID and relationship ID in error context
|
|
401
|
+
|
|
402
|
+
### Documentation
|
|
403
|
+
|
|
404
|
+
- Tool descriptions serve as primary documentation for agents
|
|
405
|
+
- JSDoc comments on interfaces for developer documentation
|
|
406
|
+
- README update for human users
|
|
407
|
+
|
|
408
|
+
### Testing Strategy
|
|
409
|
+
|
|
410
|
+
- Unit tests for each tool following existing patterns
|
|
411
|
+
- Mock QuickbaseClient for isolation
|
|
412
|
+
- Test success, validation errors, API errors, and edge cases
|
|
413
|
+
- Specific tests for destructive operation handling
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# Plan: Relationship Management
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This document outlines the phased execution plan for implementing relationship management tools in the MCP Quickbase server. The plan follows a safety-first approach: read-only operations first, then write operations with explicit safety measures for destructive actions.
|
|
6
|
+
|
|
7
|
+
## Phases
|
|
8
|
+
|
|
9
|
+
### Phase 1: Foundation - Read Operations and Domain Setup
|
|
10
|
+
|
|
11
|
+
**Objective:** Establish the relationships domain and implement the read-only `get_relationships` tool, enabling agents to explore table structures safely.
|
|
12
|
+
|
|
13
|
+
**Deliverables:**
|
|
14
|
+
- `src/tools/relationships/` directory structure
|
|
15
|
+
- `src/tools/relationships/index.ts` with registration function
|
|
16
|
+
- `src/tools/relationships/get_relationships.ts` tool implementation
|
|
17
|
+
- `src/__tests__/tools/relationships.test.ts` with tests for get_relationships
|
|
18
|
+
- Update to `src/tools/index.ts` to register relationship tools
|
|
19
|
+
|
|
20
|
+
**Agent Assignments:**
|
|
21
|
+
- implement-feature: Create directory structure and index.ts registration pattern
|
|
22
|
+
- implement-feature: Implement GetRelationshipsTool with full type definitions
|
|
23
|
+
- implement-feature: Update main tools/index.ts to include relationships
|
|
24
|
+
|
|
25
|
+
**Acceptance Criteria:**
|
|
26
|
+
- [ ] `get_relationships` tool is registered and callable
|
|
27
|
+
- [ ] Returns correct relationship structure with foreignKeyField, lookupFields, summaryFields
|
|
28
|
+
- [ ] **API response structure validated against TypeScript interfaces** - Confirm actual Quickbase API responses match documented structure before proceeding to Phase 2
|
|
29
|
+
- [ ] Pagination (skip parameter) works correctly - Verify if API supports limit parameter and adjust if needed
|
|
30
|
+
- [ ] Tool description clearly explains what information is returned
|
|
31
|
+
- [ ] Unit tests cover success case, empty results, pagination, and API errors
|
|
32
|
+
|
|
33
|
+
### Phase 2: Write Operations - Create and Update
|
|
34
|
+
|
|
35
|
+
**Objective:** Implement non-destructive write operations that allow creating and enhancing relationships.
|
|
36
|
+
|
|
37
|
+
**Deliverables:**
|
|
38
|
+
- `src/tools/relationships/create_relationship.ts` tool implementation
|
|
39
|
+
- `src/tools/relationships/update_relationship.ts` tool implementation
|
|
40
|
+
- Extended tests in `src/__tests__/tools/relationships.test.ts`
|
|
41
|
+
|
|
42
|
+
**Agent Assignments:**
|
|
43
|
+
- implement-feature: Implement CreateRelationshipTool with lookup/summary field support
|
|
44
|
+
- implement-feature: Implement UpdateRelationshipTool (additive operations only)
|
|
45
|
+
|
|
46
|
+
**Acceptance Criteria:**
|
|
47
|
+
- [ ] `create_relationship` tool creates relationships with optional lookup/summary fields
|
|
48
|
+
- [ ] Tool description emphasizes this is a SAFE operation
|
|
49
|
+
- [ ] **JSON Schema conditional validation enforced** - summary_accumulation_type is required when summary_field_id is provided
|
|
50
|
+
- [ ] `update_relationship` tool adds fields to existing relationships
|
|
51
|
+
- [ ] Update tool description clearly states "ADDITIVE ONLY"
|
|
52
|
+
- [ ] Unit tests cover: basic creation, creation with lookups, creation with summary, validation errors
|
|
53
|
+
- [ ] Unit tests cover: update adding lookups, update adding summary, relationship not found
|
|
54
|
+
- [ ] Unit tests verify conditional validation: missing accumulation_type with summary_field_id fails validation
|
|
55
|
+
|
|
56
|
+
### Phase 3: Destructive Operations with Safety Measures
|
|
57
|
+
|
|
58
|
+
**Objective:** Implement the delete operation with comprehensive safety warnings and agent guidance.
|
|
59
|
+
|
|
60
|
+
**Deliverables:**
|
|
61
|
+
- `src/tools/relationships/delete_relationship.ts` tool implementation
|
|
62
|
+
- Complete test coverage for delete scenarios
|
|
63
|
+
- Final documentation updates
|
|
64
|
+
|
|
65
|
+
**Agent Assignments:**
|
|
66
|
+
- implement-feature: Implement DeleteRelationshipTool with safety-focused description
|
|
67
|
+
- implement-feature: Ensure all tests pass and coverage threshold met
|
|
68
|
+
- implement-feature: Update exports and verify tool registration
|
|
69
|
+
|
|
70
|
+
**Acceptance Criteria:**
|
|
71
|
+
- [ ] `delete_relationship` tool description starts with "WARNING: DESTRUCTIVE OPERATION"
|
|
72
|
+
- [ ] Description explicitly lists what will be deleted (lookup fields, summary fields)
|
|
73
|
+
- [ ] Description explicitly states data is permanently lost
|
|
74
|
+
- [ ] Description recommends using `get_relationships` first to review impact
|
|
75
|
+
- [ ] Description recommends confirming with user before proceeding
|
|
76
|
+
- [ ] Unit tests cover: successful deletion, relationship not found, API errors
|
|
77
|
+
- [ ] All four tools are registered and functional
|
|
78
|
+
- [ ] Test coverage meets or exceeds 40% threshold (lines/functions/statements) and 20% branches per jest.config.js
|
|
79
|
+
|
|
80
|
+
### Phase 4: Integration and Verification
|
|
81
|
+
|
|
82
|
+
**Objective:** Verify complete integration, ensure all tests pass, and validate agent safety measures.
|
|
83
|
+
|
|
84
|
+
**Deliverables:**
|
|
85
|
+
- Passing test suite with coverage >= 40% (lines/functions/statements) and >= 20% branches per jest.config.js
|
|
86
|
+
- All linting checks pass
|
|
87
|
+
- Verified tool descriptions for agent safety
|
|
88
|
+
|
|
89
|
+
**Agent Assignments:**
|
|
90
|
+
- verify-task: Run full test suite and validate coverage
|
|
91
|
+
- verify-task: Verify all tools are properly registered
|
|
92
|
+
- verify-task: Review tool descriptions for clarity and safety warnings
|
|
93
|
+
- commit-task: Commit all changes with descriptive message
|
|
94
|
+
|
|
95
|
+
**Acceptance Criteria:**
|
|
96
|
+
- [ ] `npm test` passes all tests
|
|
97
|
+
- [ ] `npm run lint` shows no errors
|
|
98
|
+
- [ ] All four relationship tools appear in tool registry
|
|
99
|
+
- [ ] Delete tool description contains required safety warnings
|
|
100
|
+
- [ ] Integration test validates end-to-end flow (if applicable)
|
|
101
|
+
|
|
102
|
+
## Dependencies
|
|
103
|
+
|
|
104
|
+
### Cross-Phase Dependencies
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
Phase 1 (Foundation)
|
|
108
|
+
|
|
|
109
|
+
+---> Phase 2 (Create/Update) [depends on domain setup]
|
|
110
|
+
|
|
|
111
|
+
+---> Phase 3 (Delete) [depends on domain setup, benefits from Phase 2 patterns]
|
|
112
|
+
|
|
|
113
|
+
+---> Phase 4 (Verification) [depends on all implementations]
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### External Dependencies
|
|
117
|
+
|
|
118
|
+
| Dependency | Type | Status |
|
|
119
|
+
|------------|------|--------|
|
|
120
|
+
| `src/tools/base.ts` (BaseTool) | Existing | Available |
|
|
121
|
+
| `src/client/quickbase.ts` (QuickbaseClient) | Existing | Available |
|
|
122
|
+
| `src/tools/registry.ts` (toolRegistry) | Existing | Available |
|
|
123
|
+
| Quickbase Relationships API | External | Available |
|
|
124
|
+
|
|
125
|
+
## Risk Mitigation
|
|
126
|
+
|
|
127
|
+
| Risk | Probability | Impact | Mitigation |
|
|
128
|
+
|------|-------------|--------|------------|
|
|
129
|
+
| API schema differs from documentation | Medium | Medium | Start with get_relationships to validate response structure; adjust types as needed |
|
|
130
|
+
| Agent uses delete without understanding consequences | Medium | High | Comprehensive warning in tool description; recommend user confirmation |
|
|
131
|
+
| Test coverage falls below threshold | Low | Medium | Write tests concurrently with implementation; prioritize critical paths |
|
|
132
|
+
| Validation complexity for summary fields | Medium | Low | Clear error messages when accumulation_type missing; follow existing field patterns |
|
|
133
|
+
|
|
134
|
+
## Success Metrics
|
|
135
|
+
|
|
136
|
+
- [ ] All four relationship tools implemented and registered
|
|
137
|
+
- [ ] `get_relationships` returns accurate relationship data
|
|
138
|
+
- [ ] `create_relationship` successfully creates relationships with lookup/summary fields
|
|
139
|
+
- [ ] `update_relationship` adds fields without deleting existing ones
|
|
140
|
+
- [ ] `delete_relationship` has prominent destructive operation warnings
|
|
141
|
+
- [ ] Test coverage >= 40% lines/functions/statements, >= 20% branches (per jest.config.js)
|
|
142
|
+
- [ ] No lint errors
|
|
143
|
+
- [ ] Tool descriptions help agents understand when to use each tool
|
|
144
|
+
- [ ] Destructive operations clearly marked and explain consequences
|
|
145
|
+
|
|
146
|
+
## Implementation Notes
|
|
147
|
+
|
|
148
|
+
### Tool Naming Convention
|
|
149
|
+
|
|
150
|
+
Follow existing snake_case pattern:
|
|
151
|
+
- `get_relationships` (not `getRelationships`)
|
|
152
|
+
- `create_relationship` (not `createRelationship`)
|
|
153
|
+
- `update_relationship` (not `updateRelationship`)
|
|
154
|
+
- `delete_relationship` (not `deleteRelationship`)
|
|
155
|
+
|
|
156
|
+
### Parameter Naming Convention
|
|
157
|
+
|
|
158
|
+
Follow existing patterns:
|
|
159
|
+
- `table_id` (not `tableId`)
|
|
160
|
+
- `relationship_id` (not `relationshipId`)
|
|
161
|
+
- `parent_table_id` (not `parentTableId`)
|
|
162
|
+
- `lookup_field_ids` (not `lookupFieldIds`)
|
|
163
|
+
|
|
164
|
+
### Error Message Format
|
|
165
|
+
|
|
166
|
+
Include context for debugging:
|
|
167
|
+
```typescript
|
|
168
|
+
throw new Error(`Failed to get relationships for table ${tableId}: ${response.error?.message || 'Unknown error'}`);
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Logging Pattern
|
|
172
|
+
|
|
173
|
+
Use existing logger:
|
|
174
|
+
```typescript
|
|
175
|
+
const logger = createLogger('GetRelationshipsTool');
|
|
176
|
+
logger.info('Getting relationships for table', { tableId });
|
|
177
|
+
```
|