mcp-quickbase 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/CHANGELOG.md +82 -0
  2. package/LICENSE +21 -0
  3. package/README.md +301 -0
  4. package/dist/client/quickbase.d.ts +28 -0
  5. package/dist/client/quickbase.js +235 -0
  6. package/dist/client/quickbase.js.map +1 -0
  7. package/dist/mcp/index.d.ts +4 -0
  8. package/dist/mcp/index.js +21 -0
  9. package/dist/mcp/index.js.map +1 -0
  10. package/dist/mcp/server.d.ts +19 -0
  11. package/dist/mcp/server.js +102 -0
  12. package/dist/mcp/server.js.map +1 -0
  13. package/dist/mcp-stdio-server.d.ts +2 -0
  14. package/dist/mcp-stdio-server.js +168 -0
  15. package/dist/mcp-stdio-server.js.map +1 -0
  16. package/dist/server.d.ts +2 -0
  17. package/dist/server.js +318 -0
  18. package/dist/server.js.map +1 -0
  19. package/dist/tools/apps/create_app.d.ts +87 -0
  20. package/dist/tools/apps/create_app.js +87 -0
  21. package/dist/tools/apps/create_app.js.map +1 -0
  22. package/dist/tools/apps/index.d.ts +9 -0
  23. package/dist/tools/apps/index.js +40 -0
  24. package/dist/tools/apps/index.js.map +1 -0
  25. package/dist/tools/apps/list_tables.d.ts +108 -0
  26. package/dist/tools/apps/list_tables.js +100 -0
  27. package/dist/tools/apps/list_tables.js.map +1 -0
  28. package/dist/tools/apps/update_app.d.ts +91 -0
  29. package/dist/tools/apps/update_app.js +99 -0
  30. package/dist/tools/apps/update_app.js.map +1 -0
  31. package/dist/tools/base.d.ts +47 -0
  32. package/dist/tools/base.js +63 -0
  33. package/dist/tools/base.js.map +1 -0
  34. package/dist/tools/configure_cache.d.ts +81 -0
  35. package/dist/tools/configure_cache.js +77 -0
  36. package/dist/tools/configure_cache.js.map +1 -0
  37. package/dist/tools/fields/create_field.d.ts +121 -0
  38. package/dist/tools/fields/create_field.js +102 -0
  39. package/dist/tools/fields/create_field.js.map +1 -0
  40. package/dist/tools/fields/index.d.ts +8 -0
  41. package/dist/tools/fields/index.js +37 -0
  42. package/dist/tools/fields/index.js.map +1 -0
  43. package/dist/tools/fields/update_field.d.ts +112 -0
  44. package/dist/tools/fields/update_field.js +114 -0
  45. package/dist/tools/fields/update_field.js.map +1 -0
  46. package/dist/tools/files/download_file.d.ts +111 -0
  47. package/dist/tools/files/download_file.js +173 -0
  48. package/dist/tools/files/download_file.js.map +1 -0
  49. package/dist/tools/files/index.d.ts +8 -0
  50. package/dist/tools/files/index.js +37 -0
  51. package/dist/tools/files/index.js.map +1 -0
  52. package/dist/tools/files/upload_file.d.ts +107 -0
  53. package/dist/tools/files/upload_file.js +211 -0
  54. package/dist/tools/files/upload_file.js.map +1 -0
  55. package/dist/tools/index.d.ts +18 -0
  56. package/dist/tools/index.js +65 -0
  57. package/dist/tools/index.js.map +1 -0
  58. package/dist/tools/records/bulk_create_records.d.ts +75 -0
  59. package/dist/tools/records/bulk_create_records.js +104 -0
  60. package/dist/tools/records/bulk_create_records.js.map +1 -0
  61. package/dist/tools/records/bulk_update_records.d.ts +77 -0
  62. package/dist/tools/records/bulk_update_records.js +102 -0
  63. package/dist/tools/records/bulk_update_records.js.map +1 -0
  64. package/dist/tools/records/create_record.d.ts +68 -0
  65. package/dist/tools/records/create_record.js +123 -0
  66. package/dist/tools/records/create_record.js.map +1 -0
  67. package/dist/tools/records/index.d.ts +11 -0
  68. package/dist/tools/records/index.js +46 -0
  69. package/dist/tools/records/index.js.map +1 -0
  70. package/dist/tools/records/query_records.d.ts +164 -0
  71. package/dist/tools/records/query_records.js +261 -0
  72. package/dist/tools/records/query_records.js.map +1 -0
  73. package/dist/tools/records/update_record.d.ts +81 -0
  74. package/dist/tools/records/update_record.js +99 -0
  75. package/dist/tools/records/update_record.js.map +1 -0
  76. package/dist/tools/registry.d.ts +41 -0
  77. package/dist/tools/registry.js +66 -0
  78. package/dist/tools/registry.js.map +1 -0
  79. package/dist/tools/reports/index.d.ts +6 -0
  80. package/dist/tools/reports/index.js +31 -0
  81. package/dist/tools/reports/index.js.map +1 -0
  82. package/dist/tools/reports/run_report.d.ts +70 -0
  83. package/dist/tools/reports/run_report.js +72 -0
  84. package/dist/tools/reports/run_report.js.map +1 -0
  85. package/dist/tools/tables/create_table.d.ts +142 -0
  86. package/dist/tools/tables/create_table.js +119 -0
  87. package/dist/tools/tables/create_table.js.map +1 -0
  88. package/dist/tools/tables/get_table_fields.d.ts +108 -0
  89. package/dist/tools/tables/get_table_fields.js +96 -0
  90. package/dist/tools/tables/get_table_fields.js.map +1 -0
  91. package/dist/tools/tables/index.d.ts +9 -0
  92. package/dist/tools/tables/index.js +40 -0
  93. package/dist/tools/tables/index.js.map +1 -0
  94. package/dist/tools/tables/update_table.d.ts +91 -0
  95. package/dist/tools/tables/update_table.js +99 -0
  96. package/dist/tools/tables/update_table.js.map +1 -0
  97. package/dist/tools/test_connection.d.ts +51 -0
  98. package/dist/tools/test_connection.js +101 -0
  99. package/dist/tools/test_connection.js.map +1 -0
  100. package/dist/types/api.d.ts +70 -0
  101. package/dist/types/api.js +6 -0
  102. package/dist/types/api.js.map +1 -0
  103. package/dist/types/config.d.ts +49 -0
  104. package/dist/types/config.js +3 -0
  105. package/dist/types/config.js.map +1 -0
  106. package/dist/types/mcp.d.ts +55 -0
  107. package/dist/types/mcp.js +3 -0
  108. package/dist/types/mcp.js.map +1 -0
  109. package/dist/utils/cache.d.ts +87 -0
  110. package/dist/utils/cache.js +211 -0
  111. package/dist/utils/cache.js.map +1 -0
  112. package/dist/utils/file.d.ts +40 -0
  113. package/dist/utils/file.js +167 -0
  114. package/dist/utils/file.js.map +1 -0
  115. package/dist/utils/logger.d.ts +37 -0
  116. package/dist/utils/logger.js +144 -0
  117. package/dist/utils/logger.js.map +1 -0
  118. package/dist/utils/retry.d.ts +39 -0
  119. package/dist/utils/retry.js +88 -0
  120. package/dist/utils/retry.js.map +1 -0
  121. package/dist/utils/validation.d.ts +32 -0
  122. package/dist/utils/validation.js +227 -0
  123. package/dist/utils/validation.js.map +1 -0
  124. package/docs/README.md +41 -0
  125. package/docs/architecture.md +94 -0
  126. package/docs/claude-prompts.md +218 -0
  127. package/docs/deployment.md +244 -0
  128. package/docs/developer-guide.md +537 -0
  129. package/docs/final-qa-report.md +243 -0
  130. package/docs/performance-benchmarks.md +306 -0
  131. package/docs/quick-reference.md +109 -0
  132. package/docs/quickstart.md +183 -0
  133. package/docs/security-review.md +263 -0
  134. package/docs/tools.md +269 -0
  135. package/package.json +68 -0
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ /**
18
+ * MCP (Model Context Protocol) module exports
19
+ */
20
+ __exportStar(require("./server"), exports);
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA;;GAEG;AACH,2CAAyB"}
@@ -0,0 +1,19 @@
1
+ import { Request, Response } from 'express';
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
4
+ /**
5
+ * Create and configure an MCP server instance
6
+ */
7
+ export declare function createMcpServer(): McpServer;
8
+ /**
9
+ * Register tools with an existing MCP server
10
+ */
11
+ export declare function registerMcpTools(server: McpServer): void;
12
+ /**
13
+ * Create an HTTP transport for the MCP server
14
+ */
15
+ export declare function createHttpTransport(): StreamableHTTPServerTransport;
16
+ /**
17
+ * Handle an MCP request via HTTP
18
+ */
19
+ export declare function handleMcpRequest(server: McpServer, transport: StreamableHTTPServerTransport, req: Request, res: Response): Promise<void>;
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createMcpServer = createMcpServer;
4
+ exports.registerMcpTools = registerMcpTools;
5
+ exports.createHttpTransport = createHttpTransport;
6
+ exports.handleMcpRequest = handleMcpRequest;
7
+ /**
8
+ * MCP Server implementation using the official Model Context Protocol SDK
9
+ */
10
+ const crypto_1 = require("crypto");
11
+ const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
12
+ const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
13
+ const logger_1 = require("../utils/logger");
14
+ const tools_1 = require("../tools");
15
+ const validation_1 = require("../utils/validation");
16
+ const logger = (0, logger_1.createLogger)('mcp-server');
17
+ /**
18
+ * Create and configure an MCP server instance
19
+ */
20
+ function createMcpServer() {
21
+ // Initialize the MCP server with our app info
22
+ const server = new mcp_js_1.McpServer({
23
+ name: 'Quickbase MCP Server',
24
+ version: '2.0.0',
25
+ });
26
+ logger.info('MCP Server created');
27
+ return server;
28
+ }
29
+ /**
30
+ * Register tools with an existing MCP server
31
+ */
32
+ function registerMcpTools(server) {
33
+ registerTools(server);
34
+ }
35
+ /**
36
+ * Register all tools with the MCP server
37
+ */
38
+ function registerTools(server) {
39
+ const tools = tools_1.toolRegistry.getAllTools();
40
+ tools.forEach(tool => {
41
+ // Create a Zod schema from our tool's parameter schema
42
+ const schema = (0, validation_1.createMcpZodSchema)(tool.paramSchema);
43
+ // Register the tool with the MCP server
44
+ server.tool(tool.name, tool.description, schema, async (params) => {
45
+ try {
46
+ logger.info(`Executing MCP tool: ${tool.name}`);
47
+ const apiResponse = await tool.execute(params);
48
+ // Handle API response - only return the data if successful
49
+ if (!apiResponse.success || apiResponse.error) {
50
+ const errorMessage = apiResponse.error?.message || 'Tool execution failed';
51
+ logger.error(`Tool ${tool.name} failed`, { error: apiResponse.error });
52
+ throw new Error(errorMessage);
53
+ }
54
+ // Ensure proper JSON formatting by using a standardized response structure
55
+ return {
56
+ content: [{
57
+ type: 'text',
58
+ text: JSON.stringify(apiResponse.data, null, 2)
59
+ }]
60
+ };
61
+ }
62
+ catch (error) {
63
+ logger.error(`Error executing MCP tool ${tool.name}`, { error });
64
+ throw error;
65
+ }
66
+ });
67
+ logger.info(`Registered MCP tool: ${tool.name}`);
68
+ });
69
+ logger.info(`Registered ${tools.length} tools with MCP Server`);
70
+ }
71
+ /**
72
+ * Create an HTTP transport for the MCP server
73
+ */
74
+ function createHttpTransport() {
75
+ // Create a new transport with proper session management
76
+ // Following the TypeScript SDK examples for HTTP transport
77
+ return new streamableHttp_js_1.StreamableHTTPServerTransport({
78
+ sessionIdGenerator: () => (0, crypto_1.randomUUID)(),
79
+ enableJsonResponse: true
80
+ });
81
+ }
82
+ /**
83
+ * Handle an MCP request via HTTP
84
+ */
85
+ async function handleMcpRequest(server, transport, req, res) {
86
+ try {
87
+ logger.info('Handling MCP request');
88
+ await transport.handleRequest(req, res, req.body);
89
+ }
90
+ catch (error) {
91
+ logger.error('Error handling MCP request', { error });
92
+ res.status(500).json({
93
+ jsonrpc: '2.0',
94
+ error: {
95
+ code: -32000,
96
+ message: error instanceof Error ? error.message : 'Unknown error'
97
+ },
98
+ id: req.body?.id || null
99
+ });
100
+ }
101
+ }
102
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,168 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ var __importDefault = (this && this.__importDefault) || function (mod) {
37
+ return (mod && mod.__esModule) ? mod : { "default": mod };
38
+ };
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ /**
41
+ * MCP Stdio Server for Claude CLI integration
42
+ */
43
+ const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
44
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
45
+ const dotenv_1 = __importDefault(require("dotenv"));
46
+ const logger_1 = require("./utils/logger");
47
+ const quickbase_1 = require("./client/quickbase");
48
+ const cache_1 = require("./utils/cache");
49
+ const tools_1 = require("./tools");
50
+ const validation_1 = require("./utils/validation");
51
+ // Load environment variables
52
+ dotenv_1.default.config();
53
+ const logger = (0, logger_1.createLogger)('mcp-stdio-server');
54
+ /**
55
+ * Main server function
56
+ */
57
+ async function main() {
58
+ try {
59
+ // Initialize the MCP server
60
+ const server = new mcp_js_1.McpServer({
61
+ name: 'Quickbase MCP Server',
62
+ version: '2.0.0',
63
+ });
64
+ logger.info('MCP Server created');
65
+ // Initialize Quickbase client
66
+ const config = {
67
+ realmHost: process.env.QUICKBASE_REALM_HOST || '',
68
+ userToken: process.env.QUICKBASE_USER_TOKEN || '',
69
+ appId: process.env.QUICKBASE_APP_ID,
70
+ cacheEnabled: process.env.QUICKBASE_CACHE_ENABLED !== 'false',
71
+ cacheTtl: parseInt(process.env.QUICKBASE_CACHE_TTL || '3600', 10),
72
+ debug: process.env.DEBUG === 'true'
73
+ };
74
+ // Validate required configuration
75
+ if (!config.realmHost || !config.userToken) {
76
+ throw new Error('QUICKBASE_REALM_HOST and QUICKBASE_USER_TOKEN are required');
77
+ }
78
+ // Validate realm host format
79
+ if (!config.realmHost.match(/^[a-zA-Z0-9-]+\.quickbase\.com$/)) {
80
+ throw new Error('QUICKBASE_REALM_HOST must be in format: yourcompany.quickbase.com');
81
+ }
82
+ // Validate cache TTL
83
+ if (isNaN(config.cacheTtl) || config.cacheTtl <= 0) {
84
+ throw new Error('QUICKBASE_CACHE_TTL must be a positive number');
85
+ }
86
+ const quickbaseClient = new quickbase_1.QuickbaseClient(config);
87
+ const cacheService = new cache_1.CacheService(config.cacheTtl, config.cacheEnabled);
88
+ // Initialize tools
89
+ (0, tools_1.initializeTools)(quickbaseClient, cacheService);
90
+ // Register tools with MCP server
91
+ const tools = tools_1.toolRegistry.getAllTools();
92
+ tools.forEach(tool => {
93
+ const schema = (0, validation_1.createMcpZodSchema)(tool.paramSchema);
94
+ server.tool(tool.name, tool.description, schema, async (params) => {
95
+ try {
96
+ logger.info(`Executing MCP tool: ${tool.name}`);
97
+ const apiResponse = await tool.execute(params);
98
+ // Handle API response - only return the data if successful
99
+ if (!apiResponse.success || apiResponse.error) {
100
+ const errorMessage = apiResponse.error?.message || 'Tool execution failed';
101
+ logger.error(`Tool ${tool.name} failed`, { error: apiResponse.error });
102
+ throw new Error(errorMessage);
103
+ }
104
+ return {
105
+ content: [{
106
+ type: 'text',
107
+ text: JSON.stringify(apiResponse.data, null, 2)
108
+ }]
109
+ };
110
+ }
111
+ catch (error) {
112
+ logger.error(`Error executing MCP tool ${tool.name}`, { error });
113
+ throw error;
114
+ }
115
+ });
116
+ logger.info(`Registered MCP tool: ${tool.name}`);
117
+ });
118
+ logger.info(`Registered ${tools.length} tools with MCP Server`);
119
+ // Create stdio transport
120
+ const transport = new stdio_js_1.StdioServerTransport();
121
+ // Connect and run
122
+ await server.connect(transport);
123
+ logger.info('MCP server connected via stdio and ready for requests');
124
+ }
125
+ catch (error) {
126
+ logger.error('Failed to start MCP server', { error });
127
+ await gracefulShutdown();
128
+ process.exit(1);
129
+ }
130
+ }
131
+ /**
132
+ * Graceful shutdown handler
133
+ */
134
+ async function gracefulShutdown() {
135
+ try {
136
+ logger.info('Initiating graceful shutdown...');
137
+ // Give pending operations time to complete
138
+ await new Promise(resolve => setTimeout(resolve, 1000));
139
+ // Cleanup cache instances
140
+ const { CacheService } = await Promise.resolve().then(() => __importStar(require('./utils/cache.js')));
141
+ const stats = CacheService.getStats();
142
+ if (stats.instances > 0) {
143
+ logger.info(`Cleaning up ${stats.instances} cache instances`);
144
+ }
145
+ logger.info('Graceful shutdown completed');
146
+ }
147
+ catch (error) {
148
+ logger.error('Error during graceful shutdown', { error });
149
+ }
150
+ }
151
+ // Install shutdown handlers
152
+ process.on('SIGTERM', async () => {
153
+ logger.info('SIGTERM received');
154
+ await gracefulShutdown();
155
+ process.exit(0);
156
+ });
157
+ process.on('SIGINT', async () => {
158
+ logger.info('SIGINT received');
159
+ await gracefulShutdown();
160
+ process.exit(0);
161
+ });
162
+ // Start the server
163
+ main().catch(async (error) => {
164
+ logger.error('Unhandled error in main', { error });
165
+ await gracefulShutdown();
166
+ process.exit(1);
167
+ });
168
+ //# sourceMappingURL=mcp-stdio-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-stdio-server.js","sourceRoot":"","sources":["../src/mcp-stdio-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ declare const app: import("express-serve-static-core").Express;
2
+ export default app;
package/dist/server.js ADDED
@@ -0,0 +1,318 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const express_1 = __importDefault(require("express"));
7
+ const dotenv_1 = __importDefault(require("dotenv"));
8
+ const cors_1 = __importDefault(require("cors"));
9
+ const logger_1 = require("./utils/logger");
10
+ const quickbase_1 = require("./client/quickbase");
11
+ const cache_1 = require("./utils/cache");
12
+ const tools_1 = require("./tools");
13
+ const mcp_1 = require("./mcp");
14
+ // Load environment variables
15
+ dotenv_1.default.config();
16
+ const logger = (0, logger_1.createLogger)('server');
17
+ // Initialize Express app
18
+ const app = (0, express_1.default)();
19
+ app.use(express_1.default.json());
20
+ app.use((0, cors_1.default)());
21
+ // Configuration
22
+ const PORT = process.env.PORT || 3536; // Changed from 3000 to avoid port conflicts
23
+ // Initialize Quickbase client
24
+ let quickbaseClient = null;
25
+ let cacheService = null;
26
+ // Track connector status
27
+ const connectorStatus = {
28
+ status: 'disconnected',
29
+ error: null
30
+ };
31
+ // Initialize MCP server and transport
32
+ const mcpServer = (0, mcp_1.createMcpServer)();
33
+ const mcpTransport = (0, mcp_1.createHttpTransport)();
34
+ /**
35
+ * Initialize Quickbase client from environment variables
36
+ */
37
+ function initializeClient() {
38
+ try {
39
+ // Validate required environment variables
40
+ const realmHost = process.env.QUICKBASE_REALM_HOST;
41
+ const userToken = process.env.QUICKBASE_USER_TOKEN;
42
+ if (!realmHost) {
43
+ throw new Error('QUICKBASE_REALM_HOST environment variable is required');
44
+ }
45
+ if (!userToken) {
46
+ throw new Error('QUICKBASE_USER_TOKEN environment variable is required');
47
+ }
48
+ // Safely parse cache TTL with validation
49
+ const cacheTtlStr = process.env.QUICKBASE_CACHE_TTL || '3600';
50
+ const cacheTtl = parseInt(cacheTtlStr, 10);
51
+ if (isNaN(cacheTtl) || cacheTtl <= 0) {
52
+ throw new Error(`Invalid QUICKBASE_CACHE_TTL value: ${cacheTtlStr}. Must be a positive integer.`);
53
+ }
54
+ const config = {
55
+ realmHost,
56
+ userToken,
57
+ appId: process.env.QUICKBASE_APP_ID,
58
+ cacheEnabled: process.env.QUICKBASE_CACHE_ENABLED !== 'false',
59
+ cacheTtl,
60
+ debug: process.env.DEBUG === 'true'
61
+ };
62
+ quickbaseClient = new quickbase_1.QuickbaseClient(config);
63
+ cacheService = new cache_1.CacheService(config.cacheTtl, config.cacheEnabled);
64
+ // Initialize MCP tools
65
+ (0, tools_1.initializeTools)(quickbaseClient, cacheService);
66
+ // Register tools with MCP server after initialization
67
+ (0, mcp_1.registerMcpTools)(mcpServer);
68
+ connectorStatus.status = 'connected';
69
+ connectorStatus.error = null;
70
+ logger.info('Quickbase client initialized successfully');
71
+ logger.info(`Registered tools: ${tools_1.toolRegistry.getToolNames().join(', ')}`);
72
+ }
73
+ catch (error) {
74
+ connectorStatus.status = 'error';
75
+ connectorStatus.error = error instanceof Error ? error.message : 'Unknown error';
76
+ logger.error('Failed to initialize Quickbase client', { error });
77
+ }
78
+ }
79
+ // MCP tool execution endpoint
80
+ app.post('/api/:tool', async (req, res) => {
81
+ const toolName = req.params.tool;
82
+ const params = req.body || {};
83
+ logger.info(`Executing tool: ${toolName}`, { params });
84
+ if (!quickbaseClient) {
85
+ return res.status(500).json({
86
+ success: false,
87
+ error: {
88
+ message: 'Quickbase client not initialized',
89
+ type: 'ConfigurationError'
90
+ }
91
+ });
92
+ }
93
+ const tool = tools_1.toolRegistry.getTool(toolName);
94
+ if (!tool) {
95
+ return res.status(404).json({
96
+ success: false,
97
+ error: {
98
+ message: `Tool ${toolName} not found`,
99
+ type: 'NotFoundError'
100
+ }
101
+ });
102
+ }
103
+ try {
104
+ const result = await tool.execute(params);
105
+ res.json(result);
106
+ }
107
+ catch (error) {
108
+ logger.error(`Error executing tool ${toolName}`, { error });
109
+ res.status(500).json({
110
+ success: false,
111
+ error: {
112
+ message: error instanceof Error ? error.message : 'Unknown error',
113
+ type: error instanceof Error ? error.name : 'UnknownError'
114
+ }
115
+ });
116
+ }
117
+ });
118
+ // MCP batch tool execution
119
+ app.post('/api/batch', async (req, res) => {
120
+ const requests = req.body.requests || [];
121
+ if (!Array.isArray(requests) || requests.length === 0) {
122
+ return res.status(400).json({
123
+ success: false,
124
+ error: {
125
+ message: 'Invalid batch request format',
126
+ type: 'ValidationError'
127
+ }
128
+ });
129
+ }
130
+ logger.info(`Executing batch request with ${requests.length} tools`);
131
+ if (!quickbaseClient) {
132
+ return res.status(500).json({
133
+ success: false,
134
+ error: {
135
+ message: 'Quickbase client not initialized',
136
+ type: 'ConfigurationError'
137
+ }
138
+ });
139
+ }
140
+ try {
141
+ const results = await Promise.all(requests.map(async (request) => {
142
+ const tool = tools_1.toolRegistry.getTool(request.tool);
143
+ if (!tool) {
144
+ return {
145
+ tool: request.tool,
146
+ success: false,
147
+ error: {
148
+ message: `Tool ${request.tool} not found`,
149
+ type: 'NotFoundError'
150
+ }
151
+ };
152
+ }
153
+ try {
154
+ const result = await tool.execute(request.params || {});
155
+ return {
156
+ tool: request.tool,
157
+ ...result
158
+ };
159
+ }
160
+ catch (error) {
161
+ return {
162
+ tool: request.tool,
163
+ success: false,
164
+ error: {
165
+ message: error instanceof Error ? error.message : 'Unknown error',
166
+ type: error instanceof Error ? error.name : 'UnknownError'
167
+ }
168
+ };
169
+ }
170
+ }));
171
+ res.json({
172
+ success: true,
173
+ results
174
+ });
175
+ }
176
+ catch (error) {
177
+ logger.error('Error executing batch request', { error });
178
+ res.status(500).json({
179
+ success: false,
180
+ error: {
181
+ message: error instanceof Error ? error.message : 'Unknown error',
182
+ type: error instanceof Error ? error.name : 'UnknownError'
183
+ }
184
+ });
185
+ }
186
+ });
187
+ // MCP schema endpoint
188
+ app.get('/api/schema', (_req, res) => {
189
+ if (!quickbaseClient) {
190
+ return res.status(500).json({
191
+ success: false,
192
+ error: {
193
+ message: 'Quickbase client not initialized',
194
+ type: 'ConfigurationError'
195
+ }
196
+ });
197
+ }
198
+ const tools = tools_1.toolRegistry.getAllTools().map(tool => ({
199
+ name: tool.name,
200
+ description: tool.description,
201
+ schema: tool.paramSchema
202
+ }));
203
+ res.json({
204
+ success: true,
205
+ data: {
206
+ tools
207
+ }
208
+ });
209
+ });
210
+ // Status route
211
+ app.get('/status', (_req, res) => {
212
+ res.json({
213
+ name: 'Quickbase MCP Server',
214
+ version: '2.0.0',
215
+ status: connectorStatus.status,
216
+ error: connectorStatus.error,
217
+ tools: quickbaseClient ? tools_1.toolRegistry.getToolNames() : []
218
+ });
219
+ });
220
+ // MCP Protocol routes
221
+ // POST endpoint for MCP messages
222
+ app.post('/mcp', async (req, res) => {
223
+ if (!quickbaseClient) {
224
+ return res.status(500).json({
225
+ jsonrpc: '2.0',
226
+ error: {
227
+ code: -32000,
228
+ message: 'Quickbase client not initialized'
229
+ },
230
+ id: req.body?.id || null
231
+ });
232
+ }
233
+ try {
234
+ logger.info('Received MCP protocol request');
235
+ await (0, mcp_1.handleMcpRequest)(mcpServer, mcpTransport, req, res);
236
+ }
237
+ catch (error) {
238
+ logger.error('Error handling MCP protocol request', { error });
239
+ res.status(500).json({
240
+ jsonrpc: '2.0',
241
+ error: {
242
+ code: -32000,
243
+ message: error instanceof Error ? error.message : 'Unknown error'
244
+ },
245
+ id: req.body?.id || null
246
+ });
247
+ }
248
+ });
249
+ // GET endpoint for MCP long-polling notifications
250
+ app.get('/mcp', async (req, res) => {
251
+ try {
252
+ logger.info('Received MCP protocol GET request for notifications');
253
+ res.setHeader('Content-Type', 'text/event-stream');
254
+ res.setHeader('Cache-Control', 'no-cache');
255
+ res.setHeader('Connection', 'keep-alive');
256
+ // Keep connection open for server-sent events
257
+ const interval = setInterval(() => {
258
+ res.write(': keepalive\n\n');
259
+ }, 30000);
260
+ req.on('close', () => {
261
+ clearInterval(interval);
262
+ });
263
+ }
264
+ catch (error) {
265
+ logger.error('Error handling MCP protocol notifications', { error });
266
+ res.status(500).end();
267
+ }
268
+ });
269
+ // Start server
270
+ app.listen(PORT, async () => {
271
+ logger.info(`Quickbase MCP Server v2 server running on port ${PORT}`);
272
+ // Initialize Quickbase client
273
+ initializeClient();
274
+ // Connect the MCP server to its transport
275
+ try {
276
+ await mcpServer.connect(mcpTransport);
277
+ logger.info('MCP server connected successfully');
278
+ }
279
+ catch (error) {
280
+ logger.error('Failed to connect MCP server', { error });
281
+ }
282
+ });
283
+ // Graceful shutdown handling
284
+ process.on('SIGTERM', () => {
285
+ logger.info('SIGTERM received, shutting down gracefully');
286
+ cleanup();
287
+ });
288
+ process.on('SIGINT', () => {
289
+ logger.info('SIGINT received, shutting down gracefully');
290
+ cleanup();
291
+ });
292
+ process.on('uncaughtException', (error) => {
293
+ logger.error('Uncaught exception', { error });
294
+ cleanup();
295
+ process.exit(1);
296
+ });
297
+ process.on('unhandledRejection', (reason, promise) => {
298
+ logger.error('Unhandled rejection', { reason, promise });
299
+ cleanup();
300
+ process.exit(1);
301
+ });
302
+ function cleanup() {
303
+ try {
304
+ // Close cache connections
305
+ if (cacheService) {
306
+ logger.info('Closing cache service');
307
+ // Note: Cache service cleanup should be implemented if it has cleanup methods
308
+ }
309
+ // Close any other resources
310
+ logger.info('Cleanup completed');
311
+ }
312
+ catch (error) {
313
+ logger.error('Error during cleanup', { error });
314
+ }
315
+ }
316
+ // Export for testing
317
+ exports.default = app;
318
+ //# sourceMappingURL=server.js.map