mcp-quickbase 2.0.3 → 2.0.4
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/.github/workflows/claude.yml +37 -0
- package/.mcp.json +41 -0
- package/HARDENING_SUMMARY.md +84 -0
- package/README.md +84 -208
- package/dist/client/quickbase.js +32 -6
- package/dist/client/quickbase.js.map +1 -1
- package/dist/utils/file.d.ts +0 -3
- package/dist/utils/file.js +84 -12
- package/dist/utils/file.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: Claude Code
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
issue_comment:
|
|
5
|
+
types: [created]
|
|
6
|
+
pull_request_review_comment:
|
|
7
|
+
types: [created]
|
|
8
|
+
issues:
|
|
9
|
+
types: [opened, assigned]
|
|
10
|
+
pull_request_review:
|
|
11
|
+
types: [submitted]
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
claude:
|
|
15
|
+
if: |
|
|
16
|
+
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
|
|
17
|
+
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
|
|
18
|
+
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
|
|
19
|
+
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
permissions:
|
|
22
|
+
contents: read
|
|
23
|
+
pull-requests: read
|
|
24
|
+
issues: read
|
|
25
|
+
id-token: write
|
|
26
|
+
steps:
|
|
27
|
+
- name: Checkout repository
|
|
28
|
+
uses: actions/checkout@v4
|
|
29
|
+
with:
|
|
30
|
+
fetch-depth: 1
|
|
31
|
+
|
|
32
|
+
- name: Run Claude Code
|
|
33
|
+
id: claude
|
|
34
|
+
uses: anthropics/claude-code-action@beta
|
|
35
|
+
with:
|
|
36
|
+
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
37
|
+
|
package/.mcp.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mcpServers": {
|
|
3
|
+
"github": {
|
|
4
|
+
"command": "npx",
|
|
5
|
+
"args": [
|
|
6
|
+
"-y",
|
|
7
|
+
"@modelcontextprotocol/server-github"
|
|
8
|
+
],
|
|
9
|
+
"env": {
|
|
10
|
+
"GITHUB_TOKEN": "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"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"memory": {
|
|
14
|
+
"command": "docker",
|
|
15
|
+
"args": [
|
|
16
|
+
"run",
|
|
17
|
+
"-i",
|
|
18
|
+
"-v",
|
|
19
|
+
"claude-memory:/app/dist",
|
|
20
|
+
"--rm",
|
|
21
|
+
"mcp/memory"
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
"sequentialthinking": {
|
|
25
|
+
"command": "docker",
|
|
26
|
+
"args": [
|
|
27
|
+
"run",
|
|
28
|
+
"--rm",
|
|
29
|
+
"-i",
|
|
30
|
+
"mcp/sequentialthinking"
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
"context7": {
|
|
34
|
+
"command": "npx",
|
|
35
|
+
"args": [
|
|
36
|
+
"-y",
|
|
37
|
+
"@upstash/context7-mcp"
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Security Hardening and Consistency Improvements Summary
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
This document summarizes the security hardening and consistency improvements made to the MCP-Quickbase codebase.
|
|
5
|
+
|
|
6
|
+
## Critical Security Improvements
|
|
7
|
+
|
|
8
|
+
### 1. File Operations Security (HIGH PRIORITY)
|
|
9
|
+
- **Added path traversal protection** to prevent access outside working directory
|
|
10
|
+
- **Implemented file size limits** (10MB) for read/write operations
|
|
11
|
+
- **Added path sanitization** with validation before any filesystem access
|
|
12
|
+
- **Configurable working directory** via `QUICKBASE_WORKING_DIR` environment variable
|
|
13
|
+
- **Security logging** for attempted violations
|
|
14
|
+
|
|
15
|
+
### 2. Configuration Validation
|
|
16
|
+
- **Added bounds checking** for all numeric configuration values:
|
|
17
|
+
- Rate limit: 1-100 requests/second
|
|
18
|
+
- Cache TTL: 0-86400 seconds (24 hours max)
|
|
19
|
+
- Max retries: 0-10
|
|
20
|
+
- Retry delay: 100ms-60s
|
|
21
|
+
- Request timeout: 1s-5 minutes
|
|
22
|
+
- **Improved realm hostname redaction** in logs to preserve domain structure
|
|
23
|
+
|
|
24
|
+
## Consistency Improvements
|
|
25
|
+
|
|
26
|
+
### 1. Documentation
|
|
27
|
+
- **Fixed package naming inconsistency** (was `quickbase-mcp-connector`, now correctly `mcp-quickbase`)
|
|
28
|
+
- **Added community project disclaimer** with appropriate language
|
|
29
|
+
- **Updated all installation instructions** to use correct package name
|
|
30
|
+
|
|
31
|
+
### 2. Code Quality
|
|
32
|
+
- **TypeScript strict mode** is properly enabled
|
|
33
|
+
- **Consistent error handling** across all tools
|
|
34
|
+
- **Proper logging** with sensitive data redaction
|
|
35
|
+
- **Consistent file naming** (kebab-case) across the project
|
|
36
|
+
|
|
37
|
+
## Areas of Excellence
|
|
38
|
+
|
|
39
|
+
### 1. Defensive Programming
|
|
40
|
+
- **Circuit breakers** in pagination logic (query_records)
|
|
41
|
+
- **Timeout protection** (30s) for long-running operations
|
|
42
|
+
- **Rate limiting** with thread-safe implementation
|
|
43
|
+
- **Exponential backoff with jitter** in retry logic
|
|
44
|
+
|
|
45
|
+
### 2. Error Handling
|
|
46
|
+
- **Comprehensive API response validation**
|
|
47
|
+
- **Proper error propagation** from tools to MCP
|
|
48
|
+
- **Graceful shutdown handlers** for SIGTERM/SIGINT
|
|
49
|
+
- **Cache cleanup** on shutdown
|
|
50
|
+
|
|
51
|
+
### 3. Security Features
|
|
52
|
+
- **Sensitive data redaction** in logs (tokens, auth headers)
|
|
53
|
+
- **Input validation** using Zod schemas
|
|
54
|
+
- **Environment variable validation** at startup
|
|
55
|
+
- **Memory-efficient file streaming** for large files using streaming APIs (e.g., Node.js `fs.createReadStream`) to handle large files without excessive memory usage
|
|
56
|
+
|
|
57
|
+
## Remaining Improvements (Lower Priority)
|
|
58
|
+
|
|
59
|
+
### 1. Type Safety
|
|
60
|
+
- 72 ESLint warnings for `any` types in API response handling
|
|
61
|
+
- Could be improved but not critical for security
|
|
62
|
+
|
|
63
|
+
### 2. Test Coverage
|
|
64
|
+
- Current coverage: 42.57%
|
|
65
|
+
- File operations have low coverage (20%)
|
|
66
|
+
- Many tools lack dedicated test files
|
|
67
|
+
|
|
68
|
+
### 3. Code Duplication
|
|
69
|
+
- File upload tool has duplicate path validation
|
|
70
|
+
- Could be refactored to use centralized file utilities
|
|
71
|
+
|
|
72
|
+
### 4. Minor Enhancements
|
|
73
|
+
- Could add circuit breaker pattern to retry logic
|
|
74
|
+
- User token could be stored more securely (currently in config object)
|
|
75
|
+
|
|
76
|
+
## Recommendations
|
|
77
|
+
|
|
78
|
+
1. **Immediate Priority**: The file security improvements are critical and have been implemented
|
|
79
|
+
2. **Medium Priority**: Improve test coverage, especially for file operations
|
|
80
|
+
3. **Low Priority**: Address TypeScript `any` warnings for better type safety
|
|
81
|
+
4. **Future Enhancement**: Consider adding rate limiting per API endpoint
|
|
82
|
+
|
|
83
|
+
## Testing
|
|
84
|
+
All changes have been tested and pass the existing test suite. No regressions were introduced.
|
package/README.md
CHANGED
|
@@ -1,38 +1,24 @@
|
|
|
1
1
|
# Quickbase MCP Server
|
|
2
2
|
|
|
3
|
-
A TypeScript-based Model Context Protocol (MCP) connector for Quickbase, designed for seamless integration with Claude and other AI assistants.
|
|
3
|
+
A TypeScript-based Model Context Protocol (MCP) connector for Quickbase, designed for seamless integration with Claude Desktop and other AI assistants.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
> **📋 Community Project Notice**
|
|
6
|
+
> This is a community-developed integration that is not an official Quickbase product. While it uses Quickbase's public APIs, it is not officially supported by Quickbase, Inc. This project is provided "as is" and maintained by the community. For official Quickbase products and support, please visit [quickbase.com](https://www.quickbase.com).
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
## 🚀 Quick Start for Claude Desktop
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
# Use directly with npx (no installation needed)
|
|
11
|
-
npx -y mcp-quickbase
|
|
12
|
-
|
|
13
|
-
# Or install globally
|
|
14
|
-
npm install -g mcp-quickbase
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
### Installation from Source
|
|
10
|
+
### One-Line Setup Check
|
|
18
11
|
|
|
19
12
|
```bash
|
|
20
|
-
|
|
21
|
-
git clone https://github.com/danielbushman/MCP-Quickbase.git
|
|
22
|
-
cd MCP-Quickbase
|
|
23
|
-
|
|
24
|
-
# Install dependencies
|
|
25
|
-
npm install
|
|
26
|
-
|
|
27
|
-
# Build the project
|
|
28
|
-
npm run build
|
|
13
|
+
curl -fsSL https://raw.githubusercontent.com/danielbushman/MCP-Quickbase/main/check_dependencies.sh | bash
|
|
29
14
|
```
|
|
30
15
|
|
|
31
|
-
###
|
|
16
|
+
### Configure Claude Desktop
|
|
32
17
|
|
|
33
|
-
|
|
18
|
+
Add this to your Claude Desktop configuration file:
|
|
34
19
|
|
|
35
|
-
|
|
20
|
+
**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
21
|
+
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
36
22
|
|
|
37
23
|
```json
|
|
38
24
|
{
|
|
@@ -43,29 +29,44 @@ Configure directly in Claude Desktop:
|
|
|
43
29
|
"env": {
|
|
44
30
|
"QUICKBASE_REALM_HOST": "your-realm.quickbase.com",
|
|
45
31
|
"QUICKBASE_USER_TOKEN": "your-user-token",
|
|
46
|
-
"QUICKBASE_APP_ID": "your-app-id"
|
|
47
|
-
"QUICKBASE_CACHE_ENABLED": "true",
|
|
48
|
-
"QUICKBASE_CACHE_TTL": "3600"
|
|
32
|
+
"QUICKBASE_APP_ID": "your-app-id"
|
|
49
33
|
}
|
|
50
34
|
}
|
|
51
35
|
}
|
|
52
36
|
}
|
|
53
37
|
```
|
|
54
38
|
|
|
55
|
-
|
|
39
|
+
**That's it!** Restart Claude Desktop and you can start using Quickbase tools.
|
|
56
40
|
|
|
57
|
-
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 📦 Installation Options
|
|
44
|
+
|
|
45
|
+
### Option 1: NPM (Recommended)
|
|
58
46
|
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
DEBUG=false
|
|
47
|
+
```bash
|
|
48
|
+
# Use directly with npx (no installation needed)
|
|
49
|
+
npx -y mcp-quickbase
|
|
50
|
+
|
|
51
|
+
# Or install globally
|
|
52
|
+
npm install -g mcp-quickbase
|
|
66
53
|
```
|
|
67
54
|
|
|
68
|
-
|
|
55
|
+
### Option 2: From Source
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# Clone the repository
|
|
59
|
+
git clone https://github.com/danielbushman/MCP-Quickbase.git
|
|
60
|
+
cd MCP-Quickbase
|
|
61
|
+
|
|
62
|
+
# Install dependencies
|
|
63
|
+
npm install
|
|
64
|
+
|
|
65
|
+
# Build the project
|
|
66
|
+
npm run build
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
For source installation, use this Claude Desktop configuration:
|
|
69
70
|
|
|
70
71
|
```json
|
|
71
72
|
{
|
|
@@ -83,7 +84,20 @@ Then configure Claude Desktop:
|
|
|
83
84
|
}
|
|
84
85
|
```
|
|
85
86
|
|
|
86
|
-
|
|
87
|
+
## 🔧 Configuration
|
|
88
|
+
|
|
89
|
+
### Required Environment Variables
|
|
90
|
+
|
|
91
|
+
- **`QUICKBASE_REALM_HOST`** - Your Quickbase realm (e.g., `company.quickbase.com`)
|
|
92
|
+
- **`QUICKBASE_USER_TOKEN`** - Your Quickbase API token ([Get one here](https://help.quickbase.com/en/articles/8672050))
|
|
93
|
+
- **`QUICKBASE_APP_ID`** - Default application ID (optional)
|
|
94
|
+
|
|
95
|
+
### Optional Settings
|
|
96
|
+
|
|
97
|
+
- **`QUICKBASE_CACHE_ENABLED`** - Enable caching (`true`/`false`, default: `true`)
|
|
98
|
+
- **`QUICKBASE_CACHE_TTL`** - Cache duration in seconds (default: `3600`)
|
|
99
|
+
- **`DEBUG`** - Enable debug logging (`true`/`false`, default: `false`)
|
|
100
|
+
- **`LOG_LEVEL`** - Logging level (`DEBUG`/`INFO`/`WARN`/`ERROR`, default: `INFO`)
|
|
87
101
|
|
|
88
102
|
## 🛠️ Available Tools
|
|
89
103
|
|
|
@@ -98,204 +112,66 @@ Then configure Claude Desktop:
|
|
|
98
112
|
|
|
99
113
|
### Table Operations
|
|
100
114
|
- **`create_table`** - Create new tables
|
|
101
|
-
- **`update_table`** - Update
|
|
102
|
-
- **`get_table_fields`** -
|
|
115
|
+
- **`update_table`** - Update table properties
|
|
116
|
+
- **`get_table_fields`** - Get field information for a table
|
|
103
117
|
|
|
104
118
|
### Field Management
|
|
105
119
|
- **`create_field`** - Create new fields in tables
|
|
106
|
-
- **`update_field`** - Update
|
|
120
|
+
- **`update_field`** - Update field properties
|
|
107
121
|
|
|
108
122
|
### Record Operations
|
|
109
|
-
- **`query_records`** - Query records with
|
|
123
|
+
- **`query_records`** - Query records with filtering and sorting
|
|
110
124
|
- **`create_record`** - Create single records
|
|
111
125
|
- **`update_record`** - Update existing records
|
|
112
|
-
- **`bulk_create_records`** - Create multiple records
|
|
113
|
-
- **`bulk_update_records`** - Update multiple records
|
|
114
|
-
|
|
115
|
-
### File Handling
|
|
116
|
-
- **`upload_file`** - Upload files to record fields
|
|
117
|
-
- **`download_file`** - Download files from record fields
|
|
118
|
-
|
|
119
|
-
### Reports
|
|
120
|
-
- **`run_report`** - Execute Quickbase reports with filters
|
|
121
|
-
|
|
122
|
-
## 🏗️ Architecture
|
|
123
|
-
|
|
124
|
-
### TypeScript-First Design
|
|
125
|
-
- **100% TypeScript** for type safety and developer experience
|
|
126
|
-
- **Comprehensive type definitions** for all Quickbase API interactions
|
|
127
|
-
- **Modern async/await** patterns throughout
|
|
128
|
-
|
|
129
|
-
### Performance Features
|
|
130
|
-
- **Intelligent caching** with configurable TTL
|
|
131
|
-
- **Automatic retry logic** for transient failures
|
|
132
|
-
- **Bulk operations** for high-performance data manipulation
|
|
133
|
-
- **Pagination support** for large datasets
|
|
134
|
-
|
|
135
|
-
### Error Handling
|
|
136
|
-
- **Structured error responses** with detailed context
|
|
137
|
-
- **Graceful degradation** for API failures
|
|
138
|
-
- **Comprehensive logging** for debugging
|
|
139
|
-
|
|
140
|
-
## 📚 Examples
|
|
141
|
-
|
|
142
|
-
### Basic Record Operations
|
|
143
|
-
|
|
144
|
-
```typescript
|
|
145
|
-
// Query records
|
|
146
|
-
const records = await queryRecords({
|
|
147
|
-
table_id: "bqrxzt5wq",
|
|
148
|
-
where: "{6.CT.'Project'}",
|
|
149
|
-
select: ["1", "6", "7", "8"]
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
// Create a record
|
|
153
|
-
const newRecord = await createRecord({
|
|
154
|
-
table_id: "bqrxzt5wq",
|
|
155
|
-
data: {
|
|
156
|
-
"6": "New Project",
|
|
157
|
-
"7": "Project description",
|
|
158
|
-
"8": "High"
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
// Update multiple records
|
|
163
|
-
const updates = await bulkUpdateRecords({
|
|
164
|
-
table_id: "bqrxzt5wq",
|
|
165
|
-
records: [
|
|
166
|
-
{ "3": "123", "8": "Critical" },
|
|
167
|
-
{ "3": "124", "8": "Low" }
|
|
168
|
-
]
|
|
169
|
-
});
|
|
170
|
-
```
|
|
126
|
+
- **`bulk_create_records`** - Create multiple records
|
|
127
|
+
- **`bulk_update_records`** - Update multiple records
|
|
171
128
|
|
|
172
129
|
### File Operations
|
|
130
|
+
- **`upload_file`** - Upload files to file attachment fields
|
|
131
|
+
- **`download_file`** - Download files from records
|
|
173
132
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
const upload = await uploadFile({
|
|
177
|
-
table_id: "bqrxzt5wq",
|
|
178
|
-
record_id: "123",
|
|
179
|
-
field_id: "9",
|
|
180
|
-
file_path: "/path/to/document.pdf"
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
// Download a file
|
|
184
|
-
const download = await downloadFile({
|
|
185
|
-
table_id: "bqrxzt5wq",
|
|
186
|
-
record_id: "123",
|
|
187
|
-
field_id: "9",
|
|
188
|
-
output_path: "/downloads/document.pdf"
|
|
189
|
-
});
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
### Advanced Queries with Pagination
|
|
193
|
-
|
|
194
|
-
```typescript
|
|
195
|
-
// Paginated query for large datasets
|
|
196
|
-
const largeDataset = await queryRecords({
|
|
197
|
-
table_id: "bqrxzt5wq",
|
|
198
|
-
select: ["1", "6", "7", "8"],
|
|
199
|
-
paginate: true,
|
|
200
|
-
max_records: "1000",
|
|
201
|
-
options: {
|
|
202
|
-
orderBy: [{ fieldId: "6", order: "ASC" }],
|
|
203
|
-
top: 100
|
|
204
|
-
}
|
|
205
|
-
});
|
|
206
|
-
```
|
|
133
|
+
### Reporting
|
|
134
|
+
- **`run_report`** - Execute Quickbase reports
|
|
207
135
|
|
|
208
|
-
##
|
|
136
|
+
## 📚 Usage Examples
|
|
209
137
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
# Run tests with coverage
|
|
215
|
-
npm test -- --coverage
|
|
216
|
-
|
|
217
|
-
# Run tests in watch mode
|
|
218
|
-
npm test -- --watch
|
|
138
|
+
### Basic Record Query
|
|
139
|
+
```
|
|
140
|
+
Query all customers from the Customers table
|
|
219
141
|
```
|
|
220
142
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
### Project Structure
|
|
224
|
-
|
|
143
|
+
### Create a New Record
|
|
225
144
|
```
|
|
226
|
-
|
|
227
|
-
├── client/ # Quickbase API client
|
|
228
|
-
├── tools/ # MCP tool implementations
|
|
229
|
-
│ ├── apps/ # Application management tools
|
|
230
|
-
│ ├── fields/ # Field management tools
|
|
231
|
-
│ ├── files/ # File operation tools
|
|
232
|
-
│ ├── records/ # Record operation tools
|
|
233
|
-
│ ├── reports/ # Report execution tools
|
|
234
|
-
│ └── tables/ # Table operation tools
|
|
235
|
-
├── types/ # TypeScript type definitions
|
|
236
|
-
├── utils/ # Utility functions
|
|
237
|
-
└── mcp/ # MCP server implementation
|
|
145
|
+
Create a new customer record with name "Acme Corp" and status "Active"
|
|
238
146
|
```
|
|
239
147
|
|
|
240
|
-
###
|
|
241
|
-
|
|
242
|
-
1. Create tool class extending `BaseTool<TParams, TResult>`
|
|
243
|
-
2. Implement required properties and `run()` method
|
|
244
|
-
3. Register in appropriate tool category
|
|
245
|
-
4. Add comprehensive tests
|
|
246
|
-
|
|
247
|
-
Example:
|
|
248
|
-
|
|
249
|
-
```typescript
|
|
250
|
-
export class MyCustomTool extends BaseTool<MyParams, MyResult> {
|
|
251
|
-
public readonly name = 'my_custom_tool';
|
|
252
|
-
public readonly description = 'Description of my tool';
|
|
253
|
-
public readonly paramSchema = { /* JSON Schema */ };
|
|
254
|
-
|
|
255
|
-
protected async run(params: MyParams): Promise<MyResult> {
|
|
256
|
-
// Implementation
|
|
257
|
-
}
|
|
258
|
-
}
|
|
148
|
+
### Upload a File
|
|
259
149
|
```
|
|
260
|
-
|
|
261
|
-
## 🚦 Deployment
|
|
262
|
-
|
|
263
|
-
### HTTP Server Mode
|
|
264
|
-
```bash
|
|
265
|
-
npm start # Runs on port 3536
|
|
150
|
+
Upload invoice.pdf to the Documents field in record 123
|
|
266
151
|
```
|
|
267
152
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
153
|
+
## 🔒 Security
|
|
154
|
+
|
|
155
|
+
- API tokens are handled securely and never logged
|
|
156
|
+
- All file operations are sandboxed to the working directory
|
|
157
|
+
- Supports field-level permissions and access controls
|
|
272
158
|
|
|
273
159
|
## 📋 Requirements
|
|
274
160
|
|
|
275
|
-
-
|
|
276
|
-
-
|
|
277
|
-
-
|
|
278
|
-
- **Valid user token** with appropriate permissions
|
|
161
|
+
- Node.js 18 or higher
|
|
162
|
+
- Valid Quickbase account with API access
|
|
163
|
+
- Claude Desktop (for MCP integration)
|
|
279
164
|
|
|
280
165
|
## 🤝 Contributing
|
|
281
166
|
|
|
282
|
-
|
|
283
|
-
2. Create a feature branch
|
|
284
|
-
3. Add tests for new functionality
|
|
285
|
-
4. Ensure all tests pass
|
|
286
|
-
5. Submit a pull request
|
|
167
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
287
168
|
|
|
288
169
|
## 📄 License
|
|
289
170
|
|
|
290
|
-
MIT License - see LICENSE file for details.
|
|
291
|
-
|
|
292
|
-
## 🆘 Support
|
|
171
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
293
172
|
|
|
294
|
-
|
|
295
|
-
- Check the [documentation](docs/)
|
|
296
|
-
- Review the [Quick Start Guide](docs/quickstart.md)
|
|
297
|
-
- Open an issue on GitHub
|
|
298
|
-
|
|
299
|
-
---
|
|
173
|
+
## 🔗 Links
|
|
300
174
|
|
|
301
|
-
|
|
175
|
+
- [Quickbase API Documentation](https://developer.quickbase.com/)
|
|
176
|
+
- [Model Context Protocol](https://modelcontextprotocol.io/)
|
|
177
|
+
- [Claude Desktop](https://claude.ai/download)
|
package/dist/client/quickbase.js
CHANGED
|
@@ -48,14 +48,39 @@ class QuickbaseClient {
|
|
|
48
48
|
* @param config Client configuration
|
|
49
49
|
*/
|
|
50
50
|
constructor(config) {
|
|
51
|
+
// Validate and sanitize configuration
|
|
52
|
+
const rateLimit = config.rateLimit !== undefined ? config.rateLimit : 10;
|
|
53
|
+
const cacheTtl = config.cacheTtl !== undefined ? config.cacheTtl : 3600;
|
|
54
|
+
const maxRetries = config.maxRetries !== undefined ? config.maxRetries : 3;
|
|
55
|
+
const retryDelay = config.retryDelay !== undefined ? config.retryDelay : 1000;
|
|
56
|
+
const requestTimeout = config.requestTimeout !== undefined ? config.requestTimeout : 30000;
|
|
57
|
+
// Validate numeric values
|
|
58
|
+
if (rateLimit < 1 || rateLimit > 100) {
|
|
59
|
+
throw new Error('Rate limit must be between 1 and 100 requests per second');
|
|
60
|
+
}
|
|
61
|
+
if (cacheTtl < 0 || cacheTtl > 86400) { // Max 24 hours
|
|
62
|
+
throw new Error('Cache TTL must be between 0 and 86400 seconds (24 hours)');
|
|
63
|
+
}
|
|
64
|
+
if (maxRetries < 0 || maxRetries > 10) {
|
|
65
|
+
throw new Error('Max retries must be between 0 and 10');
|
|
66
|
+
}
|
|
67
|
+
if (retryDelay < 100 || retryDelay > 60000) {
|
|
68
|
+
throw new Error('Retry delay must be between 100ms and 60 seconds');
|
|
69
|
+
}
|
|
70
|
+
if (requestTimeout < 1000 || requestTimeout > 300000) { // 1s to 5 minutes
|
|
71
|
+
throw new Error('Request timeout must be between 1 second and 5 minutes');
|
|
72
|
+
}
|
|
51
73
|
this.config = {
|
|
52
74
|
userAgent: 'QuickbaseMCPConnector/2.0',
|
|
53
75
|
cacheEnabled: true,
|
|
54
|
-
cacheTtl: 3600,
|
|
55
|
-
maxRetries: 3,
|
|
56
|
-
retryDelay: 1000,
|
|
57
76
|
debug: false,
|
|
58
|
-
...config
|
|
77
|
+
...config,
|
|
78
|
+
// Override with validated values
|
|
79
|
+
cacheTtl,
|
|
80
|
+
maxRetries,
|
|
81
|
+
retryDelay,
|
|
82
|
+
requestTimeout,
|
|
83
|
+
rateLimit
|
|
59
84
|
};
|
|
60
85
|
if (!this.config.realmHost) {
|
|
61
86
|
throw new Error('Realm hostname is required');
|
|
@@ -123,8 +148,9 @@ class QuickbaseClient {
|
|
|
123
148
|
redactedHeaders.Authorization = '***REDACTED***';
|
|
124
149
|
}
|
|
125
150
|
if (redactedHeaders['QB-Realm-Hostname']) {
|
|
126
|
-
// Keep realm hostname for debugging but redact sensitive parts
|
|
127
|
-
|
|
151
|
+
// Keep realm hostname structure for debugging but redact sensitive parts
|
|
152
|
+
// Example: "company-name.quickbase.com" becomes "***.quickbase.com"
|
|
153
|
+
redactedHeaders['QB-Realm-Hostname'] = redactedHeaders['QB-Realm-Hostname'].replace(/^[^.]+/, '***');
|
|
128
154
|
}
|
|
129
155
|
logger.debug('Sending API request', {
|
|
130
156
|
url: url.replace(/[?&]userToken=[^&]*/g, '&userToken=***REDACTED***'), // Redact tokens in URL too
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quickbase.js","sourceRoot":"","sources":["../../src/client/quickbase.ts"],"names":[],"mappings":";;;AAEA,0CAA8C;AAC9C,4CAA+C;AAC/C,0CAAyD;AAEzD,MAAM,MAAM,GAAG,IAAA,qBAAY,EAAC,iBAAiB,CAAC,CAAC;AAE/C;;GAEG;AACH,MAAM,WAAW;IAMf,YAAY,cAAsB,EAAE,EAAE,WAAmB,IAAI;QALrD,aAAQ,GAAa,EAAE,CAAC;QAGxB,YAAO,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAC;QAGjD,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,IAAI;QACR,6DAA6D;QAC7D,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC;QAC9D,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAEO,KAAK,CAAC,cAAc;QAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEvB,6CAA6C;QAC7C,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QAEzE,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YAC7C,mDAAmD;YACnD,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;YACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,GAAG,CAAC,GAAG,GAAG,aAAa,CAAC,GAAG,EAAE,CAAC,CAAC,eAAe;YAE5E,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;gBACjB,MAAM,CAAC,KAAK,CAAC,0BAA0B,QAAQ,IAAI,CAAC,CAAC;gBACrD,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;gBAE5D,gEAAgE;gBAChE,OAAO,IAAI,CAAC,cAAc,EAAE,CAAC;YAC/B,CAAC;QACH,CAAC;QAED,iCAAiC;QACjC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IACjC,CAAC;CACF;AAED;;GAEG;AACH,MAAa,eAAe;IAO1B;;;OAGG;IACH,YAAY,MAAuB;QACjC,IAAI,CAAC,MAAM,GAAG;
|
|
1
|
+
{"version":3,"file":"quickbase.js","sourceRoot":"","sources":["../../src/client/quickbase.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/file.d.ts
CHANGED
package/dist/utils/file.js
CHANGED
|
@@ -43,8 +43,40 @@ const path = __importStar(require("path"));
|
|
|
43
43
|
const logger_1 = require("./logger");
|
|
44
44
|
const logger = (0, logger_1.createLogger)('FileUtil');
|
|
45
45
|
/**
|
|
46
|
-
* Utility functions for file operations
|
|
46
|
+
* Utility functions for file operations with security hardening
|
|
47
47
|
*/
|
|
48
|
+
// Maximum file size for reads (10MB)
|
|
49
|
+
const MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
50
|
+
// Get the working directory (can be overridden by environment variable)
|
|
51
|
+
const WORKING_DIR = process.env.QUICKBASE_WORKING_DIR || process.cwd();
|
|
52
|
+
/**
|
|
53
|
+
* Validate and sanitize a file path to prevent directory traversal
|
|
54
|
+
* @param filePath The file path to validate
|
|
55
|
+
* @returns Sanitized absolute path or null if invalid
|
|
56
|
+
*/
|
|
57
|
+
function sanitizePath(filePath) {
|
|
58
|
+
try {
|
|
59
|
+
// Resolve to absolute path
|
|
60
|
+
const absolutePath = path.resolve(WORKING_DIR, filePath);
|
|
61
|
+
// Ensure the path is within the working directory
|
|
62
|
+
const relative = path.relative(WORKING_DIR, absolutePath);
|
|
63
|
+
// Check for directory traversal attempts
|
|
64
|
+
if (relative.startsWith('..') || path.isAbsolute(relative)) {
|
|
65
|
+
logger.error('Path traversal attempt detected', {
|
|
66
|
+
filePath,
|
|
67
|
+
absolutePath,
|
|
68
|
+
relative,
|
|
69
|
+
workingDir: WORKING_DIR
|
|
70
|
+
});
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
return absolutePath;
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
logger.error('Error sanitizing path', { filePath, error });
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
48
80
|
/**
|
|
49
81
|
* Check if a file exists
|
|
50
82
|
* @param filePath File path to check
|
|
@@ -52,7 +84,11 @@ const logger = (0, logger_1.createLogger)('FileUtil');
|
|
|
52
84
|
*/
|
|
53
85
|
function fileExists(filePath) {
|
|
54
86
|
try {
|
|
55
|
-
|
|
87
|
+
const safePath = sanitizePath(filePath);
|
|
88
|
+
if (!safePath) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
return fs.existsSync(safePath) && fs.statSync(safePath).isFile();
|
|
56
92
|
}
|
|
57
93
|
catch (error) {
|
|
58
94
|
logger.error('Error checking if file exists', { filePath, error });
|
|
@@ -66,11 +102,15 @@ function fileExists(filePath) {
|
|
|
66
102
|
*/
|
|
67
103
|
function ensureDirectoryExists(dirPath) {
|
|
68
104
|
try {
|
|
69
|
-
|
|
70
|
-
|
|
105
|
+
const safePath = sanitizePath(dirPath);
|
|
106
|
+
if (!safePath) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
if (fs.existsSync(safePath)) {
|
|
110
|
+
return fs.statSync(safePath).isDirectory();
|
|
71
111
|
}
|
|
72
112
|
// Create the directory
|
|
73
|
-
fs.mkdirSync(
|
|
113
|
+
fs.mkdirSync(safePath, { recursive: true });
|
|
74
114
|
return true;
|
|
75
115
|
}
|
|
76
116
|
catch (error) {
|
|
@@ -85,10 +125,11 @@ function ensureDirectoryExists(dirPath) {
|
|
|
85
125
|
*/
|
|
86
126
|
function getFileInfo(filePath) {
|
|
87
127
|
try {
|
|
88
|
-
|
|
128
|
+
const safePath = sanitizePath(filePath);
|
|
129
|
+
if (!safePath || !fileExists(filePath)) {
|
|
89
130
|
return null;
|
|
90
131
|
}
|
|
91
|
-
const stats = fs.statSync(
|
|
132
|
+
const stats = fs.statSync(safePath);
|
|
92
133
|
const ext = path.extname(filePath).toLowerCase();
|
|
93
134
|
// Simple mime type mapping
|
|
94
135
|
const mimeTypes = {
|
|
@@ -132,11 +173,26 @@ function getFileInfo(filePath) {
|
|
|
132
173
|
*/
|
|
133
174
|
function readFileAsBuffer(filePath) {
|
|
134
175
|
try {
|
|
176
|
+
const safePath = sanitizePath(filePath);
|
|
177
|
+
if (!safePath) {
|
|
178
|
+
logger.error('Invalid file path', { filePath });
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
135
181
|
if (!fileExists(filePath)) {
|
|
136
182
|
logger.error('File does not exist', { filePath });
|
|
137
183
|
return null;
|
|
138
184
|
}
|
|
139
|
-
|
|
185
|
+
// Check file size before reading
|
|
186
|
+
const stats = fs.statSync(safePath);
|
|
187
|
+
if (stats.size > MAX_FILE_SIZE) {
|
|
188
|
+
logger.error('File too large', {
|
|
189
|
+
filePath,
|
|
190
|
+
size: stats.size,
|
|
191
|
+
maxSize: MAX_FILE_SIZE
|
|
192
|
+
});
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
return fs.readFileSync(safePath);
|
|
140
196
|
}
|
|
141
197
|
catch (error) {
|
|
142
198
|
logger.error('Error reading file', { filePath, error });
|
|
@@ -151,12 +207,28 @@ function readFileAsBuffer(filePath) {
|
|
|
151
207
|
*/
|
|
152
208
|
function writeFile(filePath, data) {
|
|
153
209
|
try {
|
|
154
|
-
const
|
|
155
|
-
if (!
|
|
156
|
-
logger.error('
|
|
210
|
+
const safePath = sanitizePath(filePath);
|
|
211
|
+
if (!safePath) {
|
|
212
|
+
logger.error('Invalid file path', { filePath });
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
const dirPath = path.dirname(safePath);
|
|
216
|
+
const safeDirPath = sanitizePath(dirPath);
|
|
217
|
+
if (!safeDirPath || !ensureDirectoryExists(safeDirPath)) {
|
|
218
|
+
logger.error('Could not create directory for file', { dirPath: safeDirPath });
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
// Check data size limit
|
|
222
|
+
const dataSize = Buffer.isBuffer(data) ? data.length : Buffer.byteLength(data);
|
|
223
|
+
if (dataSize > MAX_FILE_SIZE) {
|
|
224
|
+
logger.error('Data too large to write', {
|
|
225
|
+
filePath,
|
|
226
|
+
size: dataSize,
|
|
227
|
+
maxSize: MAX_FILE_SIZE
|
|
228
|
+
});
|
|
157
229
|
return false;
|
|
158
230
|
}
|
|
159
|
-
fs.writeFileSync(
|
|
231
|
+
fs.writeFileSync(safePath, data);
|
|
160
232
|
return true;
|
|
161
233
|
}
|
|
162
234
|
catch (error) {
|
package/dist/utils/file.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file.js","sourceRoot":"","sources":["../../src/utils/file.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"file.js","sourceRoot":"","sources":["../../src/utils/file.ts"],"names":[],"mappings":"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"}
|