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
package/dist/mcp-stdio-server.js
CHANGED
|
@@ -50,7 +50,7 @@ const tools_1 = require("./tools");
|
|
|
50
50
|
const validation_1 = require("./utils/validation");
|
|
51
51
|
// Load environment variables
|
|
52
52
|
dotenv_1.default.config();
|
|
53
|
-
const logger = (0, logger_1.createLogger)(
|
|
53
|
+
const logger = (0, logger_1.createLogger)("mcp-stdio-server");
|
|
54
54
|
/**
|
|
55
55
|
* Main server function
|
|
56
56
|
*/
|
|
@@ -58,75 +58,86 @@ async function main() {
|
|
|
58
58
|
try {
|
|
59
59
|
// Initialize the MCP server
|
|
60
60
|
const server = new mcp_js_1.McpServer({
|
|
61
|
-
name:
|
|
62
|
-
version:
|
|
61
|
+
name: "Quickbase MCP Server",
|
|
62
|
+
version: "2.0.0",
|
|
63
63
|
});
|
|
64
|
-
logger.info(
|
|
64
|
+
logger.info("MCP Server created");
|
|
65
65
|
// Check if environment variables are configured
|
|
66
66
|
const hasConfig = process.env.QUICKBASE_REALM_HOST && process.env.QUICKBASE_USER_TOKEN;
|
|
67
67
|
if (!hasConfig) {
|
|
68
|
-
logger.warn(
|
|
69
|
-
logger.info(
|
|
70
|
-
logger.info(
|
|
68
|
+
logger.warn("Quickbase configuration not found in environment variables");
|
|
69
|
+
logger.info("Server will start but tools will not be functional until configuration is provided");
|
|
70
|
+
logger.info("Required environment variables: QUICKBASE_REALM_HOST, QUICKBASE_USER_TOKEN");
|
|
71
71
|
}
|
|
72
72
|
let quickbaseClient = null;
|
|
73
73
|
let cacheService = null;
|
|
74
74
|
if (hasConfig) {
|
|
75
75
|
// Initialize Quickbase client with configuration
|
|
76
76
|
const config = {
|
|
77
|
-
realmHost: process.env.QUICKBASE_REALM_HOST ||
|
|
78
|
-
userToken: process.env.QUICKBASE_USER_TOKEN ||
|
|
77
|
+
realmHost: process.env.QUICKBASE_REALM_HOST || "",
|
|
78
|
+
userToken: process.env.QUICKBASE_USER_TOKEN || "",
|
|
79
79
|
appId: process.env.QUICKBASE_APP_ID,
|
|
80
|
-
cacheEnabled: process.env.QUICKBASE_CACHE_ENABLED !==
|
|
81
|
-
cacheTtl: parseInt(process.env.QUICKBASE_CACHE_TTL ||
|
|
82
|
-
debug: process.env.DEBUG ===
|
|
80
|
+
cacheEnabled: process.env.QUICKBASE_CACHE_ENABLED !== "false",
|
|
81
|
+
cacheTtl: parseInt(process.env.QUICKBASE_CACHE_TTL || "3600", 10),
|
|
82
|
+
debug: process.env.DEBUG === "true",
|
|
83
83
|
};
|
|
84
84
|
// Validate realm host format if provided
|
|
85
|
-
if (config.realmHost &&
|
|
86
|
-
|
|
87
|
-
logger.
|
|
85
|
+
if (config.realmHost &&
|
|
86
|
+
!config.realmHost.match(/^[a-zA-Z0-9-]+\.quickbase\.com$/)) {
|
|
87
|
+
logger.error("QUICKBASE_REALM_HOST must be in format: yourcompany.quickbase.com");
|
|
88
|
+
logger.warn("Continuing without Quickbase client initialization");
|
|
88
89
|
}
|
|
89
90
|
else {
|
|
90
91
|
// Validate cache TTL
|
|
91
92
|
if (isNaN(config.cacheTtl) || config.cacheTtl <= 0) {
|
|
92
93
|
config.cacheTtl = 3600; // Default to 1 hour
|
|
93
|
-
logger.warn(
|
|
94
|
+
logger.warn("Invalid QUICKBASE_CACHE_TTL, using default: 3600");
|
|
94
95
|
}
|
|
95
96
|
try {
|
|
96
97
|
quickbaseClient = new quickbase_1.QuickbaseClient(config);
|
|
97
98
|
cacheService = new cache_1.CacheService(config.cacheTtl, config.cacheEnabled);
|
|
98
99
|
// Initialize tools
|
|
99
100
|
(0, tools_1.initializeTools)(quickbaseClient, cacheService);
|
|
100
|
-
logger.info(
|
|
101
|
+
logger.info("Quickbase client and tools initialized successfully");
|
|
101
102
|
}
|
|
102
103
|
catch (error) {
|
|
103
|
-
logger.error(
|
|
104
|
-
logger.warn(
|
|
104
|
+
logger.error("Failed to initialize Quickbase client", { error });
|
|
105
|
+
logger.warn("Server will continue without functional tools");
|
|
105
106
|
}
|
|
106
107
|
}
|
|
107
108
|
}
|
|
108
109
|
// Register a configuration check tool that's always available
|
|
109
|
-
server.tool(
|
|
110
|
+
server.tool("check_configuration", "Check if Quickbase configuration is properly set up", {}, async () => {
|
|
110
111
|
const configured = !!quickbaseClient;
|
|
111
|
-
const status = configured
|
|
112
|
-
|
|
113
|
-
|
|
112
|
+
const status = configured
|
|
113
|
+
? "Quickbase client is configured and ready"
|
|
114
|
+
: "Quickbase client is not configured. Please set QUICKBASE_REALM_HOST and QUICKBASE_USER_TOKEN environment variables";
|
|
114
115
|
return {
|
|
115
|
-
content: [
|
|
116
|
-
|
|
116
|
+
content: [
|
|
117
|
+
{
|
|
118
|
+
type: "text",
|
|
117
119
|
text: JSON.stringify({
|
|
118
120
|
configured,
|
|
119
121
|
status,
|
|
120
|
-
requiredVars: [
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
122
|
+
requiredVars: [
|
|
123
|
+
"QUICKBASE_REALM_HOST",
|
|
124
|
+
"QUICKBASE_USER_TOKEN",
|
|
125
|
+
],
|
|
126
|
+
optionalVars: [
|
|
127
|
+
"QUICKBASE_APP_ID",
|
|
128
|
+
"QUICKBASE_CACHE_ENABLED",
|
|
129
|
+
"QUICKBASE_CACHE_TTL",
|
|
130
|
+
"DEBUG",
|
|
131
|
+
],
|
|
132
|
+
}, null, 2),
|
|
133
|
+
},
|
|
134
|
+
],
|
|
124
135
|
};
|
|
125
136
|
});
|
|
126
137
|
// Register tools with MCP server if client is initialized
|
|
127
138
|
if (quickbaseClient) {
|
|
128
139
|
const tools = tools_1.toolRegistry.getAllTools();
|
|
129
|
-
tools.forEach(tool => {
|
|
140
|
+
tools.forEach((tool) => {
|
|
130
141
|
const schema = (0, validation_1.createMcpZodSchema)(tool.paramSchema);
|
|
131
142
|
server.tool(tool.name, tool.description, schema, async (params) => {
|
|
132
143
|
try {
|
|
@@ -134,15 +145,19 @@ async function main() {
|
|
|
134
145
|
const apiResponse = await tool.execute(params);
|
|
135
146
|
// Handle API response - only return the data if successful
|
|
136
147
|
if (!apiResponse.success || apiResponse.error) {
|
|
137
|
-
const errorMessage = apiResponse.error?.message ||
|
|
138
|
-
logger.error(`Tool ${tool.name} failed`, {
|
|
148
|
+
const errorMessage = apiResponse.error?.message || "Tool execution failed";
|
|
149
|
+
logger.error(`Tool ${tool.name} failed`, {
|
|
150
|
+
error: apiResponse.error,
|
|
151
|
+
});
|
|
139
152
|
throw new Error(errorMessage);
|
|
140
153
|
}
|
|
141
154
|
return {
|
|
142
|
-
content: [
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
155
|
+
content: [
|
|
156
|
+
{
|
|
157
|
+
type: "text",
|
|
158
|
+
text: JSON.stringify(apiResponse.data, null, 2),
|
|
159
|
+
},
|
|
160
|
+
],
|
|
146
161
|
};
|
|
147
162
|
}
|
|
148
163
|
catch (error) {
|
|
@@ -155,16 +170,16 @@ async function main() {
|
|
|
155
170
|
logger.info(`Registered ${tools.length} Quickbase tools with MCP Server`);
|
|
156
171
|
}
|
|
157
172
|
else {
|
|
158
|
-
logger.info(
|
|
173
|
+
logger.info("No Quickbase tools registered (configuration missing)");
|
|
159
174
|
}
|
|
160
175
|
// Create stdio transport
|
|
161
176
|
const transport = new stdio_js_1.StdioServerTransport();
|
|
162
177
|
// Connect and run
|
|
163
178
|
await server.connect(transport);
|
|
164
|
-
logger.info(
|
|
179
|
+
logger.info("MCP server connected via stdio and ready for requests");
|
|
165
180
|
}
|
|
166
181
|
catch (error) {
|
|
167
|
-
logger.error(
|
|
182
|
+
logger.error("Failed to start MCP server", { error });
|
|
168
183
|
await gracefulShutdown();
|
|
169
184
|
process.exit(1);
|
|
170
185
|
}
|
|
@@ -174,35 +189,35 @@ async function main() {
|
|
|
174
189
|
*/
|
|
175
190
|
async function gracefulShutdown() {
|
|
176
191
|
try {
|
|
177
|
-
logger.info(
|
|
192
|
+
logger.info("Initiating graceful shutdown...");
|
|
178
193
|
// Give pending operations time to complete
|
|
179
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
194
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
180
195
|
// Cleanup cache instances
|
|
181
|
-
const { CacheService } = await Promise.resolve().then(() => __importStar(require(
|
|
196
|
+
const { CacheService } = await Promise.resolve().then(() => __importStar(require("./utils/cache.js")));
|
|
182
197
|
const stats = CacheService.getStats();
|
|
183
198
|
if (stats.instances > 0) {
|
|
184
199
|
logger.info(`Cleaning up ${stats.instances} cache instances`);
|
|
185
200
|
}
|
|
186
|
-
logger.info(
|
|
201
|
+
logger.info("Graceful shutdown completed");
|
|
187
202
|
}
|
|
188
203
|
catch (error) {
|
|
189
|
-
logger.error(
|
|
204
|
+
logger.error("Error during graceful shutdown", { error });
|
|
190
205
|
}
|
|
191
206
|
}
|
|
192
207
|
// Install shutdown handlers
|
|
193
|
-
process.on(
|
|
194
|
-
logger.info(
|
|
208
|
+
process.on("SIGTERM", async () => {
|
|
209
|
+
logger.info("SIGTERM received");
|
|
195
210
|
await gracefulShutdown();
|
|
196
211
|
process.exit(0);
|
|
197
212
|
});
|
|
198
|
-
process.on(
|
|
199
|
-
logger.info(
|
|
213
|
+
process.on("SIGINT", async () => {
|
|
214
|
+
logger.info("SIGINT received");
|
|
200
215
|
await gracefulShutdown();
|
|
201
216
|
process.exit(0);
|
|
202
217
|
});
|
|
203
218
|
// Start the server
|
|
204
219
|
main().catch(async (error) => {
|
|
205
|
-
logger.error(
|
|
220
|
+
logger.error("Unhandled error in main", { error });
|
|
206
221
|
await gracefulShutdown();
|
|
207
222
|
process.exit(1);
|
|
208
223
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-stdio-server.js","sourceRoot":"","sources":["../src/mcp-stdio-server.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA;;GAEG;AACH,oEAAoE;AACpE,wEAAiF;AACjF,oDAA4B;AAC5B,2CAA8C;AAC9C,kDAAqD;AAErD,yCAA6C;AAC7C,mCAAwD;AACxD,mDAAwD;AAExD,6BAA6B;AAC7B,gBAAM,CAAC,MAAM,EAAE,CAAC;AAEhB,MAAM,MAAM,GAAG,IAAA,qBAAY,EAAC,kBAAkB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"mcp-stdio-server.js","sourceRoot":"","sources":["../src/mcp-stdio-server.ts"],"names":[],"mappings":"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"}
|
package/dist/server.js
CHANGED
|
@@ -13,7 +13,7 @@ const tools_1 = require("./tools");
|
|
|
13
13
|
const mcp_1 = require("./mcp");
|
|
14
14
|
// Load environment variables
|
|
15
15
|
dotenv_1.default.config();
|
|
16
|
-
const logger = (0, logger_1.createLogger)(
|
|
16
|
+
const logger = (0, logger_1.createLogger)("server");
|
|
17
17
|
// Initialize Express app
|
|
18
18
|
const app = (0, express_1.default)();
|
|
19
19
|
app.use(express_1.default.json());
|
|
@@ -25,8 +25,8 @@ let quickbaseClient = null;
|
|
|
25
25
|
let cacheService = null;
|
|
26
26
|
// Track connector status
|
|
27
27
|
const connectorStatus = {
|
|
28
|
-
status:
|
|
29
|
-
error: null
|
|
28
|
+
status: "disconnected",
|
|
29
|
+
error: null,
|
|
30
30
|
};
|
|
31
31
|
// Initialize MCP server and transport
|
|
32
32
|
const mcpServer = (0, mcp_1.createMcpServer)();
|
|
@@ -40,13 +40,13 @@ function initializeClient() {
|
|
|
40
40
|
const realmHost = process.env.QUICKBASE_REALM_HOST;
|
|
41
41
|
const userToken = process.env.QUICKBASE_USER_TOKEN;
|
|
42
42
|
if (!realmHost) {
|
|
43
|
-
throw new Error(
|
|
43
|
+
throw new Error("QUICKBASE_REALM_HOST environment variable is required");
|
|
44
44
|
}
|
|
45
45
|
if (!userToken) {
|
|
46
|
-
throw new Error(
|
|
46
|
+
throw new Error("QUICKBASE_USER_TOKEN environment variable is required");
|
|
47
47
|
}
|
|
48
48
|
// Safely parse cache TTL with validation
|
|
49
|
-
const cacheTtlStr = process.env.QUICKBASE_CACHE_TTL ||
|
|
49
|
+
const cacheTtlStr = process.env.QUICKBASE_CACHE_TTL || "3600";
|
|
50
50
|
const cacheTtl = parseInt(cacheTtlStr, 10);
|
|
51
51
|
if (isNaN(cacheTtl) || cacheTtl <= 0) {
|
|
52
52
|
throw new Error(`Invalid QUICKBASE_CACHE_TTL value: ${cacheTtlStr}. Must be a positive integer.`);
|
|
@@ -55,9 +55,9 @@ function initializeClient() {
|
|
|
55
55
|
realmHost,
|
|
56
56
|
userToken,
|
|
57
57
|
appId: process.env.QUICKBASE_APP_ID,
|
|
58
|
-
cacheEnabled: process.env.QUICKBASE_CACHE_ENABLED !==
|
|
58
|
+
cacheEnabled: process.env.QUICKBASE_CACHE_ENABLED !== "false",
|
|
59
59
|
cacheTtl,
|
|
60
|
-
debug: process.env.DEBUG ===
|
|
60
|
+
debug: process.env.DEBUG === "true",
|
|
61
61
|
};
|
|
62
62
|
quickbaseClient = new quickbase_1.QuickbaseClient(config);
|
|
63
63
|
cacheService = new cache_1.CacheService(config.cacheTtl, config.cacheEnabled);
|
|
@@ -65,19 +65,20 @@ function initializeClient() {
|
|
|
65
65
|
(0, tools_1.initializeTools)(quickbaseClient, cacheService);
|
|
66
66
|
// Register tools with MCP server after initialization
|
|
67
67
|
(0, mcp_1.registerMcpTools)(mcpServer);
|
|
68
|
-
connectorStatus.status =
|
|
68
|
+
connectorStatus.status = "connected";
|
|
69
69
|
connectorStatus.error = null;
|
|
70
|
-
logger.info(
|
|
71
|
-
logger.info(`Registered tools: ${tools_1.toolRegistry.getToolNames().join(
|
|
70
|
+
logger.info("Quickbase client initialized successfully");
|
|
71
|
+
logger.info(`Registered tools: ${tools_1.toolRegistry.getToolNames().join(", ")}`);
|
|
72
72
|
}
|
|
73
73
|
catch (error) {
|
|
74
|
-
connectorStatus.status =
|
|
75
|
-
connectorStatus.error =
|
|
76
|
-
|
|
74
|
+
connectorStatus.status = "error";
|
|
75
|
+
connectorStatus.error =
|
|
76
|
+
error instanceof Error ? error.message : "Unknown error";
|
|
77
|
+
logger.error("Failed to initialize Quickbase client", { error });
|
|
77
78
|
}
|
|
78
79
|
}
|
|
79
80
|
// MCP tool execution endpoint
|
|
80
|
-
app.post(
|
|
81
|
+
app.post("/api/:tool", async (req, res) => {
|
|
81
82
|
const toolName = req.params.tool;
|
|
82
83
|
const params = req.body || {};
|
|
83
84
|
logger.info(`Executing tool: ${toolName}`, { params });
|
|
@@ -85,9 +86,9 @@ app.post('/api/:tool', async (req, res) => {
|
|
|
85
86
|
return res.status(500).json({
|
|
86
87
|
success: false,
|
|
87
88
|
error: {
|
|
88
|
-
message:
|
|
89
|
-
type:
|
|
90
|
-
}
|
|
89
|
+
message: "Quickbase client not initialized",
|
|
90
|
+
type: "ConfigurationError",
|
|
91
|
+
},
|
|
91
92
|
});
|
|
92
93
|
}
|
|
93
94
|
const tool = tools_1.toolRegistry.getTool(toolName);
|
|
@@ -96,8 +97,8 @@ app.post('/api/:tool', async (req, res) => {
|
|
|
96
97
|
success: false,
|
|
97
98
|
error: {
|
|
98
99
|
message: `Tool ${toolName} not found`,
|
|
99
|
-
type:
|
|
100
|
-
}
|
|
100
|
+
type: "NotFoundError",
|
|
101
|
+
},
|
|
101
102
|
});
|
|
102
103
|
}
|
|
103
104
|
try {
|
|
@@ -109,22 +110,22 @@ app.post('/api/:tool', async (req, res) => {
|
|
|
109
110
|
res.status(500).json({
|
|
110
111
|
success: false,
|
|
111
112
|
error: {
|
|
112
|
-
message: error instanceof Error ? error.message :
|
|
113
|
-
type: error instanceof Error ? error.name :
|
|
114
|
-
}
|
|
113
|
+
message: error instanceof Error ? error.message : "Unknown error",
|
|
114
|
+
type: error instanceof Error ? error.name : "UnknownError",
|
|
115
|
+
},
|
|
115
116
|
});
|
|
116
117
|
}
|
|
117
118
|
});
|
|
118
119
|
// MCP batch tool execution
|
|
119
|
-
app.post(
|
|
120
|
+
app.post("/api/batch", async (req, res) => {
|
|
120
121
|
const requests = req.body.requests || [];
|
|
121
122
|
if (!Array.isArray(requests) || requests.length === 0) {
|
|
122
123
|
return res.status(400).json({
|
|
123
124
|
success: false,
|
|
124
125
|
error: {
|
|
125
|
-
message:
|
|
126
|
-
type:
|
|
127
|
-
}
|
|
126
|
+
message: "Invalid batch request format",
|
|
127
|
+
type: "ValidationError",
|
|
128
|
+
},
|
|
128
129
|
});
|
|
129
130
|
}
|
|
130
131
|
logger.info(`Executing batch request with ${requests.length} tools`);
|
|
@@ -132,9 +133,9 @@ app.post('/api/batch', async (req, res) => {
|
|
|
132
133
|
return res.status(500).json({
|
|
133
134
|
success: false,
|
|
134
135
|
error: {
|
|
135
|
-
message:
|
|
136
|
-
type:
|
|
137
|
-
}
|
|
136
|
+
message: "Quickbase client not initialized",
|
|
137
|
+
type: "ConfigurationError",
|
|
138
|
+
},
|
|
138
139
|
});
|
|
139
140
|
}
|
|
140
141
|
try {
|
|
@@ -146,15 +147,15 @@ app.post('/api/batch', async (req, res) => {
|
|
|
146
147
|
success: false,
|
|
147
148
|
error: {
|
|
148
149
|
message: `Tool ${request.tool} not found`,
|
|
149
|
-
type:
|
|
150
|
-
}
|
|
150
|
+
type: "NotFoundError",
|
|
151
|
+
},
|
|
151
152
|
};
|
|
152
153
|
}
|
|
153
154
|
try {
|
|
154
155
|
const result = await tool.execute(request.params || {});
|
|
155
156
|
return {
|
|
156
157
|
tool: request.tool,
|
|
157
|
-
...result
|
|
158
|
+
...result,
|
|
158
159
|
};
|
|
159
160
|
}
|
|
160
161
|
catch (error) {
|
|
@@ -162,107 +163,107 @@ app.post('/api/batch', async (req, res) => {
|
|
|
162
163
|
tool: request.tool,
|
|
163
164
|
success: false,
|
|
164
165
|
error: {
|
|
165
|
-
message: error instanceof Error ? error.message :
|
|
166
|
-
type: error instanceof Error ? error.name :
|
|
167
|
-
}
|
|
166
|
+
message: error instanceof Error ? error.message : "Unknown error",
|
|
167
|
+
type: error instanceof Error ? error.name : "UnknownError",
|
|
168
|
+
},
|
|
168
169
|
};
|
|
169
170
|
}
|
|
170
171
|
}));
|
|
171
172
|
res.json({
|
|
172
173
|
success: true,
|
|
173
|
-
results
|
|
174
|
+
results,
|
|
174
175
|
});
|
|
175
176
|
}
|
|
176
177
|
catch (error) {
|
|
177
|
-
logger.error(
|
|
178
|
+
logger.error("Error executing batch request", { error });
|
|
178
179
|
res.status(500).json({
|
|
179
180
|
success: false,
|
|
180
181
|
error: {
|
|
181
|
-
message: error instanceof Error ? error.message :
|
|
182
|
-
type: error instanceof Error ? error.name :
|
|
183
|
-
}
|
|
182
|
+
message: error instanceof Error ? error.message : "Unknown error",
|
|
183
|
+
type: error instanceof Error ? error.name : "UnknownError",
|
|
184
|
+
},
|
|
184
185
|
});
|
|
185
186
|
}
|
|
186
187
|
});
|
|
187
188
|
// MCP schema endpoint
|
|
188
|
-
app.get(
|
|
189
|
+
app.get("/api/schema", (_req, res) => {
|
|
189
190
|
if (!quickbaseClient) {
|
|
190
191
|
return res.status(500).json({
|
|
191
192
|
success: false,
|
|
192
193
|
error: {
|
|
193
|
-
message:
|
|
194
|
-
type:
|
|
195
|
-
}
|
|
194
|
+
message: "Quickbase client not initialized",
|
|
195
|
+
type: "ConfigurationError",
|
|
196
|
+
},
|
|
196
197
|
});
|
|
197
198
|
}
|
|
198
|
-
const tools = tools_1.toolRegistry.getAllTools().map(tool => ({
|
|
199
|
+
const tools = tools_1.toolRegistry.getAllTools().map((tool) => ({
|
|
199
200
|
name: tool.name,
|
|
200
201
|
description: tool.description,
|
|
201
|
-
schema: tool.paramSchema
|
|
202
|
+
schema: tool.paramSchema,
|
|
202
203
|
}));
|
|
203
204
|
res.json({
|
|
204
205
|
success: true,
|
|
205
206
|
data: {
|
|
206
|
-
tools
|
|
207
|
-
}
|
|
207
|
+
tools,
|
|
208
|
+
},
|
|
208
209
|
});
|
|
209
210
|
});
|
|
210
211
|
// Status route
|
|
211
|
-
app.get(
|
|
212
|
+
app.get("/status", (_req, res) => {
|
|
212
213
|
res.json({
|
|
213
|
-
name:
|
|
214
|
-
version:
|
|
214
|
+
name: "Quickbase MCP Server",
|
|
215
|
+
version: "2.0.0",
|
|
215
216
|
status: connectorStatus.status,
|
|
216
217
|
error: connectorStatus.error,
|
|
217
|
-
tools: quickbaseClient ? tools_1.toolRegistry.getToolNames() : []
|
|
218
|
+
tools: quickbaseClient ? tools_1.toolRegistry.getToolNames() : [],
|
|
218
219
|
});
|
|
219
220
|
});
|
|
220
221
|
// MCP Protocol routes
|
|
221
222
|
// POST endpoint for MCP messages
|
|
222
|
-
app.post(
|
|
223
|
+
app.post("/mcp", async (req, res) => {
|
|
223
224
|
if (!quickbaseClient) {
|
|
224
225
|
return res.status(500).json({
|
|
225
|
-
jsonrpc:
|
|
226
|
+
jsonrpc: "2.0",
|
|
226
227
|
error: {
|
|
227
228
|
code: -32000,
|
|
228
|
-
message:
|
|
229
|
+
message: "Quickbase client not initialized",
|
|
229
230
|
},
|
|
230
|
-
id: req.body?.id || null
|
|
231
|
+
id: req.body?.id || null,
|
|
231
232
|
});
|
|
232
233
|
}
|
|
233
234
|
try {
|
|
234
|
-
logger.info(
|
|
235
|
+
logger.info("Received MCP protocol request");
|
|
235
236
|
await (0, mcp_1.handleMcpRequest)(mcpServer, mcpTransport, req, res);
|
|
236
237
|
}
|
|
237
238
|
catch (error) {
|
|
238
|
-
logger.error(
|
|
239
|
+
logger.error("Error handling MCP protocol request", { error });
|
|
239
240
|
res.status(500).json({
|
|
240
|
-
jsonrpc:
|
|
241
|
+
jsonrpc: "2.0",
|
|
241
242
|
error: {
|
|
242
243
|
code: -32000,
|
|
243
|
-
message: error instanceof Error ? error.message :
|
|
244
|
+
message: error instanceof Error ? error.message : "Unknown error",
|
|
244
245
|
},
|
|
245
|
-
id: req.body?.id || null
|
|
246
|
+
id: req.body?.id || null,
|
|
246
247
|
});
|
|
247
248
|
}
|
|
248
249
|
});
|
|
249
250
|
// GET endpoint for MCP long-polling notifications
|
|
250
|
-
app.get(
|
|
251
|
+
app.get("/mcp", async (req, res) => {
|
|
251
252
|
try {
|
|
252
|
-
logger.info(
|
|
253
|
-
res.setHeader(
|
|
254
|
-
res.setHeader(
|
|
255
|
-
res.setHeader(
|
|
253
|
+
logger.info("Received MCP protocol GET request for notifications");
|
|
254
|
+
res.setHeader("Content-Type", "text/event-stream");
|
|
255
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
256
|
+
res.setHeader("Connection", "keep-alive");
|
|
256
257
|
// Keep connection open for server-sent events
|
|
257
258
|
const interval = setInterval(() => {
|
|
258
|
-
res.write(
|
|
259
|
+
res.write(": keepalive\n\n");
|
|
259
260
|
}, 30000);
|
|
260
|
-
req.on(
|
|
261
|
+
req.on("close", () => {
|
|
261
262
|
clearInterval(interval);
|
|
262
263
|
});
|
|
263
264
|
}
|
|
264
265
|
catch (error) {
|
|
265
|
-
logger.error(
|
|
266
|
+
logger.error("Error handling MCP protocol notifications", { error });
|
|
266
267
|
res.status(500).end();
|
|
267
268
|
}
|
|
268
269
|
});
|
|
@@ -274,28 +275,28 @@ app.listen(PORT, async () => {
|
|
|
274
275
|
// Connect the MCP server to its transport
|
|
275
276
|
try {
|
|
276
277
|
await mcpServer.connect(mcpTransport);
|
|
277
|
-
logger.info(
|
|
278
|
+
logger.info("MCP server connected successfully");
|
|
278
279
|
}
|
|
279
280
|
catch (error) {
|
|
280
|
-
logger.error(
|
|
281
|
+
logger.error("Failed to connect MCP server", { error });
|
|
281
282
|
}
|
|
282
283
|
});
|
|
283
284
|
// Graceful shutdown handling
|
|
284
|
-
process.on(
|
|
285
|
-
logger.info(
|
|
285
|
+
process.on("SIGTERM", () => {
|
|
286
|
+
logger.info("SIGTERM received, shutting down gracefully");
|
|
286
287
|
cleanup();
|
|
287
288
|
});
|
|
288
|
-
process.on(
|
|
289
|
-
logger.info(
|
|
289
|
+
process.on("SIGINT", () => {
|
|
290
|
+
logger.info("SIGINT received, shutting down gracefully");
|
|
290
291
|
cleanup();
|
|
291
292
|
});
|
|
292
|
-
process.on(
|
|
293
|
-
logger.error(
|
|
293
|
+
process.on("uncaughtException", (error) => {
|
|
294
|
+
logger.error("Uncaught exception", { error });
|
|
294
295
|
cleanup();
|
|
295
296
|
process.exit(1);
|
|
296
297
|
});
|
|
297
|
-
process.on(
|
|
298
|
-
logger.error(
|
|
298
|
+
process.on("unhandledRejection", (reason, promise) => {
|
|
299
|
+
logger.error("Unhandled rejection", { reason, promise });
|
|
299
300
|
cleanup();
|
|
300
301
|
process.exit(1);
|
|
301
302
|
});
|
|
@@ -303,14 +304,14 @@ function cleanup() {
|
|
|
303
304
|
try {
|
|
304
305
|
// Close cache connections
|
|
305
306
|
if (cacheService) {
|
|
306
|
-
logger.info(
|
|
307
|
+
logger.info("Closing cache service");
|
|
307
308
|
// Note: Cache service cleanup should be implemented if it has cleanup methods
|
|
308
309
|
}
|
|
309
310
|
// Close any other resources
|
|
310
|
-
logger.info(
|
|
311
|
+
logger.info("Cleanup completed");
|
|
311
312
|
}
|
|
312
313
|
catch (error) {
|
|
313
|
-
logger.error(
|
|
314
|
+
logger.error("Error during cleanup", { error });
|
|
314
315
|
}
|
|
315
316
|
}
|
|
316
317
|
// Export for testing
|