@aibuilders/mcp-coach-server 1.0.9 → 1.0.10
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/dist/index.js +141 -45
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -16,6 +16,46 @@ const packageJson = JSON.parse(readFileSync(join(__dirname, "../package.json"),
|
|
|
16
16
|
const PACKAGE_VERSION = packageJson.version;
|
|
17
17
|
const CACHE_DIR = join(homedir(), ".ai-builders-mcp-cache");
|
|
18
18
|
const DEPLOYMENT_GUIDE_CACHE = join(CACHE_DIR, "deployment_guide_cache.json");
|
|
19
|
+
const OPENAPI_SPEC_CACHE = join(CACHE_DIR, "openapi_spec_cache.json");
|
|
20
|
+
const CACHE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
21
|
+
const API_ORIGIN = "https://space.ai-builders.com";
|
|
22
|
+
const DEFAULT_API_BASE_URL = `${API_ORIGIN}/backend`;
|
|
23
|
+
const OPENAPI_SPEC_URL = `${DEFAULT_API_BASE_URL}/openapi.json`;
|
|
24
|
+
const DEPLOYMENT_GUIDE_URL = `${API_ORIGIN}/deployment-prompt.md`;
|
|
25
|
+
function isCacheFresh(cachedAt) {
|
|
26
|
+
if (!cachedAt) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
const cachedTime = new Date(cachedAt);
|
|
30
|
+
if (Number.isNaN(cachedTime.getTime())) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
return Date.now() - cachedTime.getTime() < CACHE_TTL_MS;
|
|
34
|
+
}
|
|
35
|
+
function isMissingFileError(error) {
|
|
36
|
+
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
37
|
+
}
|
|
38
|
+
function deriveBaseUrl(openapiSpec) {
|
|
39
|
+
let baseUrl = DEFAULT_API_BASE_URL;
|
|
40
|
+
try {
|
|
41
|
+
if (openapiSpec?.servers?.length) {
|
|
42
|
+
const url = openapiSpec.servers[0].url;
|
|
43
|
+
if (typeof url === "string" && url.startsWith("http")) {
|
|
44
|
+
baseUrl = url;
|
|
45
|
+
}
|
|
46
|
+
else if (typeof url === "string") {
|
|
47
|
+
baseUrl = `${API_ORIGIN}${url}`;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
console.error("Failed to derive base URL from OpenAPI spec:", error);
|
|
53
|
+
}
|
|
54
|
+
return baseUrl;
|
|
55
|
+
}
|
|
56
|
+
function getSdkBaseUrl(baseUrl) {
|
|
57
|
+
return baseUrl.endsWith('/v1') ? baseUrl : `${baseUrl}/v1`;
|
|
58
|
+
}
|
|
19
59
|
async function ensureCacheDir() {
|
|
20
60
|
try {
|
|
21
61
|
await access(CACHE_DIR);
|
|
@@ -65,14 +105,17 @@ async function getCachedDeploymentGuide() {
|
|
|
65
105
|
const cacheData = JSON.parse(cacheContent);
|
|
66
106
|
const cachedTime = new Date(cacheData.cached_at);
|
|
67
107
|
const now = new Date();
|
|
68
|
-
if (now.getTime() - cachedTime.getTime() <
|
|
108
|
+
if (now.getTime() - cachedTime.getTime() < CACHE_TTL_MS) {
|
|
69
109
|
return cacheData;
|
|
70
110
|
}
|
|
71
111
|
}
|
|
72
|
-
catch {
|
|
112
|
+
catch (error) {
|
|
113
|
+
if (!isMissingFileError(error)) {
|
|
114
|
+
console.error("Deployment guide cache read failed:", error);
|
|
115
|
+
}
|
|
73
116
|
}
|
|
74
117
|
try {
|
|
75
|
-
const response = await fetch(
|
|
118
|
+
const response = await fetch(DEPLOYMENT_GUIDE_URL);
|
|
76
119
|
if (response.ok) {
|
|
77
120
|
const content = await response.text();
|
|
78
121
|
const cacheData = {
|
|
@@ -98,6 +141,60 @@ async function getCachedDeploymentGuide() {
|
|
|
98
141
|
source: "default"
|
|
99
142
|
};
|
|
100
143
|
}
|
|
144
|
+
async function getCachedOpenApiSpec(forceRefresh = false) {
|
|
145
|
+
await ensureCacheDir();
|
|
146
|
+
let cachedSpec = null;
|
|
147
|
+
try {
|
|
148
|
+
const cacheContent = await readFile(OPENAPI_SPEC_CACHE, "utf-8");
|
|
149
|
+
cachedSpec = JSON.parse(cacheContent);
|
|
150
|
+
if (cachedSpec && !forceRefresh && isCacheFresh(cachedSpec.cached_at)) {
|
|
151
|
+
return {
|
|
152
|
+
spec: cachedSpec.spec,
|
|
153
|
+
cached_at: cachedSpec.cached_at,
|
|
154
|
+
source: "cache"
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
if (!isMissingFileError(error)) {
|
|
160
|
+
console.error("OpenAPI cache read failed:", error);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
try {
|
|
164
|
+
const response = await fetch(OPENAPI_SPEC_URL);
|
|
165
|
+
if (!response.ok) {
|
|
166
|
+
throw new Error(`Failed to fetch OpenAPI specification: HTTP ${response.status}`);
|
|
167
|
+
}
|
|
168
|
+
const spec = await response.json();
|
|
169
|
+
const cacheData = {
|
|
170
|
+
spec,
|
|
171
|
+
cached_at: new Date().toISOString(),
|
|
172
|
+
url: OPENAPI_SPEC_URL
|
|
173
|
+
};
|
|
174
|
+
try {
|
|
175
|
+
await writeFile(OPENAPI_SPEC_CACHE, JSON.stringify(cacheData, null, 2));
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
console.error("OpenAPI cache write failed:", error);
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
spec,
|
|
182
|
+
cached_at: cacheData.cached_at,
|
|
183
|
+
source: "remote"
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
if (cachedSpec?.spec) {
|
|
188
|
+
console.error("Failed to fetch OpenAPI specification; using stale cache:", error);
|
|
189
|
+
return {
|
|
190
|
+
spec: cachedSpec.spec,
|
|
191
|
+
cached_at: cachedSpec.cached_at,
|
|
192
|
+
source: "stale_cache"
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
throw error;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
101
198
|
const server = new Server({
|
|
102
199
|
name: "ai-builder-mcp",
|
|
103
200
|
version: PACKAGE_VERSION,
|
|
@@ -111,32 +208,24 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
111
208
|
try {
|
|
112
209
|
switch (name) {
|
|
113
210
|
case "get_api_specification": {
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const openapiSpec = await response.json();
|
|
119
|
-
let baseUrl = "https://space.ai-builders.com/backend";
|
|
120
|
-
try {
|
|
121
|
-
if (openapiSpec?.servers?.length) {
|
|
122
|
-
const url = openapiSpec.servers[0].url;
|
|
123
|
-
if (url.startsWith("http")) {
|
|
124
|
-
baseUrl = url;
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
127
|
-
baseUrl = `https://space.ai-builders.com${url}`;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
catch { }
|
|
211
|
+
const forceRefresh = args?.force_refresh === true;
|
|
212
|
+
const cachedOpenApi = await getCachedOpenApiSpec(forceRefresh);
|
|
213
|
+
const openapiSpec = cachedOpenApi.spec;
|
|
214
|
+
const baseUrl = deriveBaseUrl(openapiSpec);
|
|
132
215
|
// For OpenAI SDK, baseURL should include /v1 since SDK appends paths directly
|
|
133
|
-
const sdkBaseUrl = baseUrl
|
|
216
|
+
const sdkBaseUrl = getSdkBaseUrl(baseUrl);
|
|
134
217
|
return {
|
|
135
218
|
content: [
|
|
136
219
|
{
|
|
137
220
|
type: "text",
|
|
138
221
|
text: JSON.stringify({
|
|
139
222
|
openapi_spec: openapiSpec,
|
|
223
|
+
cache: {
|
|
224
|
+
source: cachedOpenApi.source,
|
|
225
|
+
cached_at: cachedOpenApi.cached_at,
|
|
226
|
+
ttl_hours: 24,
|
|
227
|
+
openapi_spec_url: OPENAPI_SPEC_URL
|
|
228
|
+
},
|
|
140
229
|
endpoint_info: {
|
|
141
230
|
base_url: baseUrl,
|
|
142
231
|
description: "Base URL for the AI Builders API",
|
|
@@ -334,32 +423,26 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
334
423
|
};
|
|
335
424
|
}
|
|
336
425
|
case "get_base_url": {
|
|
337
|
-
|
|
426
|
+
const forceRefresh = args?.force_refresh === true;
|
|
427
|
+
let baseUrl = DEFAULT_API_BASE_URL;
|
|
338
428
|
let source = "default";
|
|
429
|
+
let cache = null;
|
|
339
430
|
try {
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
else {
|
|
350
|
-
baseUrl = `https://space.ai-builders.com${url}`;
|
|
351
|
-
}
|
|
352
|
-
source = "openapi_spec";
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
catch { }
|
|
356
|
-
}
|
|
431
|
+
const cachedOpenApi = await getCachedOpenApiSpec(forceRefresh);
|
|
432
|
+
baseUrl = deriveBaseUrl(cachedOpenApi.spec);
|
|
433
|
+
source = "openapi_spec";
|
|
434
|
+
cache = {
|
|
435
|
+
source: cachedOpenApi.source,
|
|
436
|
+
cached_at: cachedOpenApi.cached_at,
|
|
437
|
+
ttl_hours: 24,
|
|
438
|
+
openapi_spec_url: OPENAPI_SPEC_URL
|
|
439
|
+
};
|
|
357
440
|
}
|
|
358
441
|
catch (error) {
|
|
359
|
-
|
|
442
|
+
console.error("Failed to fetch OpenAPI specification for base URL; using default:", error);
|
|
360
443
|
}
|
|
361
444
|
// For OpenAI SDK, baseURL should include /v1 since SDK appends paths directly
|
|
362
|
-
const sdkBaseUrl = baseUrl
|
|
445
|
+
const sdkBaseUrl = getSdkBaseUrl(baseUrl);
|
|
363
446
|
return {
|
|
364
447
|
content: [
|
|
365
448
|
{
|
|
@@ -367,7 +450,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
367
450
|
text: JSON.stringify({
|
|
368
451
|
base_url: baseUrl,
|
|
369
452
|
sdk_base_url: sdkBaseUrl,
|
|
370
|
-
source
|
|
453
|
+
source,
|
|
454
|
+
cache,
|
|
371
455
|
prompt_for_ai: `The base URL for AI Builders Space API is: ${baseUrl}
|
|
372
456
|
|
|
373
457
|
This is the base URL you should use for all API calls to the AI Builders Space platform. When making HTTP requests, prepend this base URL to the API endpoint paths.
|
|
@@ -449,7 +533,13 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
449
533
|
description: "Retrieve the OpenAPI specification with endpoint details",
|
|
450
534
|
inputSchema: {
|
|
451
535
|
type: "object",
|
|
452
|
-
properties: {
|
|
536
|
+
properties: {
|
|
537
|
+
force_refresh: {
|
|
538
|
+
type: "boolean",
|
|
539
|
+
description: "Bypass the 24-hour OpenAPI cache and fetch the latest specification",
|
|
540
|
+
default: false
|
|
541
|
+
}
|
|
542
|
+
}
|
|
453
543
|
}
|
|
454
544
|
},
|
|
455
545
|
{
|
|
@@ -493,7 +583,13 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
493
583
|
description: "Get the base URL for AI Builders Space API. This tool provides a direct way to retrieve the base URL without parsing the deployment guide.",
|
|
494
584
|
inputSchema: {
|
|
495
585
|
type: "object",
|
|
496
|
-
properties: {
|
|
586
|
+
properties: {
|
|
587
|
+
force_refresh: {
|
|
588
|
+
type: "boolean",
|
|
589
|
+
description: "Bypass the 24-hour OpenAPI cache and fetch the latest specification",
|
|
590
|
+
default: false
|
|
591
|
+
}
|
|
592
|
+
}
|
|
497
593
|
}
|
|
498
594
|
}
|
|
499
595
|
]
|