@aibuilders/mcp-coach-server 1.0.8 → 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 +215 -23
- 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",
|
|
@@ -333,6 +422,89 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
333
422
|
]
|
|
334
423
|
};
|
|
335
424
|
}
|
|
425
|
+
case "get_base_url": {
|
|
426
|
+
const forceRefresh = args?.force_refresh === true;
|
|
427
|
+
let baseUrl = DEFAULT_API_BASE_URL;
|
|
428
|
+
let source = "default";
|
|
429
|
+
let cache = null;
|
|
430
|
+
try {
|
|
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
|
+
};
|
|
440
|
+
}
|
|
441
|
+
catch (error) {
|
|
442
|
+
console.error("Failed to fetch OpenAPI specification for base URL; using default:", error);
|
|
443
|
+
}
|
|
444
|
+
// For OpenAI SDK, baseURL should include /v1 since SDK appends paths directly
|
|
445
|
+
const sdkBaseUrl = getSdkBaseUrl(baseUrl);
|
|
446
|
+
return {
|
|
447
|
+
content: [
|
|
448
|
+
{
|
|
449
|
+
type: "text",
|
|
450
|
+
text: JSON.stringify({
|
|
451
|
+
base_url: baseUrl,
|
|
452
|
+
sdk_base_url: sdkBaseUrl,
|
|
453
|
+
source,
|
|
454
|
+
cache,
|
|
455
|
+
prompt_for_ai: `The base URL for AI Builders Space API is: ${baseUrl}
|
|
456
|
+
|
|
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.
|
|
458
|
+
|
|
459
|
+
For example:
|
|
460
|
+
- Full endpoint URL: ${baseUrl}/v1/chat/completions
|
|
461
|
+
- Full endpoint URL: ${baseUrl}/v1/deployments
|
|
462
|
+
|
|
463
|
+
If you are using the OpenAI SDK (recommended), use this base URL: ${sdkBaseUrl}
|
|
464
|
+
|
|
465
|
+
The base URL is also documented in the deployment guide, but this tool provides a direct way to retrieve it without parsing the full deployment guide.`,
|
|
466
|
+
usage_examples: {
|
|
467
|
+
direct_http: {
|
|
468
|
+
description: "Direct HTTP requests",
|
|
469
|
+
base_url: baseUrl,
|
|
470
|
+
example: `const response = await fetch('${baseUrl}/v1/chat/completions', {
|
|
471
|
+
method: 'POST',
|
|
472
|
+
headers: {
|
|
473
|
+
'Authorization': \`Bearer \${process.env.AI_BUILDER_TOKEN}\`,
|
|
474
|
+
'Content-Type': 'application/json'
|
|
475
|
+
},
|
|
476
|
+
body: JSON.stringify({ model: 'grok-4-fast', messages: [...] })
|
|
477
|
+
});`
|
|
478
|
+
},
|
|
479
|
+
openai_sdk: {
|
|
480
|
+
description: "OpenAI SDK (recommended)",
|
|
481
|
+
base_url: sdkBaseUrl,
|
|
482
|
+
example_node: `import OpenAI from 'openai';
|
|
483
|
+
|
|
484
|
+
const openai = new OpenAI({
|
|
485
|
+
baseURL: '${sdkBaseUrl}',
|
|
486
|
+
apiKey: process.env.AI_BUILDER_TOKEN,
|
|
487
|
+
});`,
|
|
488
|
+
example_python: `from openai import OpenAI
|
|
489
|
+
import os
|
|
490
|
+
|
|
491
|
+
client = OpenAI(
|
|
492
|
+
base_url='${sdkBaseUrl}',
|
|
493
|
+
api_key=os.getenv('AI_BUILDER_TOKEN')
|
|
494
|
+
)`
|
|
495
|
+
}
|
|
496
|
+
},
|
|
497
|
+
important_notes: [
|
|
498
|
+
"Always use this base URL when making API calls to AI Builders Space",
|
|
499
|
+
"The base URL includes the /backend path",
|
|
500
|
+
"For OpenAI SDK compatibility, use the sdk_base_url which includes /v1",
|
|
501
|
+
"All API calls require authentication via AI_BUILDER_TOKEN in the Authorization header"
|
|
502
|
+
]
|
|
503
|
+
}, null, 2)
|
|
504
|
+
}
|
|
505
|
+
]
|
|
506
|
+
};
|
|
507
|
+
}
|
|
336
508
|
default:
|
|
337
509
|
throw new Error(`Unknown tool: ${name}`);
|
|
338
510
|
}
|
|
@@ -361,7 +533,13 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
361
533
|
description: "Retrieve the OpenAPI specification with endpoint details",
|
|
362
534
|
inputSchema: {
|
|
363
535
|
type: "object",
|
|
364
|
-
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
|
+
}
|
|
365
543
|
}
|
|
366
544
|
},
|
|
367
545
|
{
|
|
@@ -399,6 +577,20 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
399
577
|
}
|
|
400
578
|
}
|
|
401
579
|
}
|
|
580
|
+
},
|
|
581
|
+
{
|
|
582
|
+
name: "get_base_url",
|
|
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.",
|
|
584
|
+
inputSchema: {
|
|
585
|
+
type: "object",
|
|
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
|
+
}
|
|
593
|
+
}
|
|
402
594
|
}
|
|
403
595
|
]
|
|
404
596
|
};
|