@cachly-dev/mcp-server 0.10.83 → 0.10.84
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/src/auth.d.ts +14 -0
- package/dist/src/auth.js +35 -0
- package/dist/src/auth.js.map +1 -1
- package/dist/src/handlers/brain.js +8 -1
- package/dist/src/handlers/brain.js.map +1 -1
- package/dist/src/index.js +67 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/telemetry-types.d.ts +1 -1
- package/dist/src/toolspecs.d.ts +43 -0
- package/dist/src/toolspecs.js +121 -0
- package/dist/src/toolspecs.js.map +1 -0
- package/package.json +1 -1
- package/server.json +2 -2
package/dist/src/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { jwtExpiryMs, checkJwt, handleApiError, diagnoseAuth, planAuthHeal } from './auth.js';
|
|
2
|
+
import { jwtExpiryMs, checkJwt, handleApiError, diagnoseAuth, planAuthHeal, readClientCredentialsFromEnv, buildClientCredentialsBody, clientCredentialsTokenUrl } from './auth.js';
|
|
3
3
|
import { handleTcoTool } from './handlers/tco.js';
|
|
4
4
|
import { notify } from './notifier.js';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
@@ -65,7 +65,7 @@ import { Redis } from 'ioredis';
|
|
|
65
65
|
let API_URL = process.env.CACHLY_API_URL ?? 'https://api.cachly.dev';
|
|
66
66
|
let JWT = process.env.CACHLY_JWT ?? '';
|
|
67
67
|
const _EMBED_MODEL = process.env.CACHLY_EMBED_MODEL ?? '';
|
|
68
|
-
const CURRENT_VERSION = '0.10.
|
|
68
|
+
const CURRENT_VERSION = '0.10.84';
|
|
69
69
|
// Max time to wait for a freshly-provisioned instance to become "running" before
|
|
70
70
|
// giving up. Free-tier provisioning in high-latency regions can take 45–90s, so the
|
|
71
71
|
// old hard-coded 25s caused spurious "instance_not_reachable" on first run.
|
|
@@ -1977,6 +1977,36 @@ if (process.argv[2] === 'publish') {
|
|
|
1977
1977
|
}
|
|
1978
1978
|
process.exit(0);
|
|
1979
1979
|
}
|
|
1980
|
+
// ── CLI: cachly tool-specs / openapi ───────────────────────────────────────────
|
|
1981
|
+
// Emit the 114-tool surface in any agent framework's dialect, derived from the
|
|
1982
|
+
// single TOOLS source of truth. Lets OpenAI Assistants, the Anthropic Messages
|
|
1983
|
+
// API, LangChain, CrewAI and AutoGen wrap cachly without hand-written glue.
|
|
1984
|
+
// npx @cachly-dev/mcp-server tool-specs --format=openai > cachly.openai.json
|
|
1985
|
+
// npx @cachly-dev/mcp-server openapi > cachly.openapi.json
|
|
1986
|
+
if (process.argv[2] === 'tool-specs' || process.argv[2] === 'openapi') {
|
|
1987
|
+
const { renderToolSpecs } = await import('./toolspecs.js');
|
|
1988
|
+
// Accept both "--format openai" and "--format=openai".
|
|
1989
|
+
let format = 'openapi';
|
|
1990
|
+
if (process.argv[2] !== 'openapi') {
|
|
1991
|
+
const eqArg = process.argv.find(a => a.startsWith('--format='));
|
|
1992
|
+
if (eqArg) {
|
|
1993
|
+
format = eqArg.slice('--format='.length);
|
|
1994
|
+
}
|
|
1995
|
+
else {
|
|
1996
|
+
const fmtFlag = process.argv.indexOf('--format');
|
|
1997
|
+
if (fmtFlag !== -1)
|
|
1998
|
+
format = process.argv[fmtFlag + 1] ?? 'openapi';
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
const valid = ['openapi', 'openai', 'anthropic', 'langchain'];
|
|
2002
|
+
if (!valid.includes(format)) {
|
|
2003
|
+
process.stderr.write(`\n❌ Unknown format "${format}". Use one of: ${valid.join(', ')}\n\n`);
|
|
2004
|
+
process.exit(1);
|
|
2005
|
+
}
|
|
2006
|
+
// Exit only after stdout has fully flushed — on a pipe, write() is async and an
|
|
2007
|
+
// immediate process.exit() truncates large payloads (~64KB) mid-flush.
|
|
2008
|
+
process.stdout.write(renderToolSpecs(TOOLS, format, CURRENT_VERSION) + '\n', () => process.exit(0));
|
|
2009
|
+
}
|
|
1980
2010
|
// ── CLI: cachly badge ─────────────────────────────────────────────────────────
|
|
1981
2011
|
// Outputs the Markdown + HTML snippet for embedding a live Brain lesson-count
|
|
1982
2012
|
// badge in any README or website. Badge SVG served by cachly API (public, no auth).
|
|
@@ -3103,6 +3133,40 @@ if (process.argv[2] === 'learn-git') {
|
|
|
3103
3133
|
process.exit(0);
|
|
3104
3134
|
}
|
|
3105
3135
|
// ── Start ─────────────────────────────────────────────────────────────────────
|
|
3136
|
+
// M2M / headless auth: if no JWT but client credentials are present, run the
|
|
3137
|
+
// OAuth2 client_credentials grant before any credential-missing handling. This
|
|
3138
|
+
// makes cachly fully non-interactive for CI runners, agent orchestrators and
|
|
3139
|
+
// AI-to-AI pipelines — no device flow, no human, no browser.
|
|
3140
|
+
if (!JWT) {
|
|
3141
|
+
const creds = readClientCredentialsFromEnv();
|
|
3142
|
+
if (creds) {
|
|
3143
|
+
try {
|
|
3144
|
+
const res = await fetch(clientCredentialsTokenUrl(creds), {
|
|
3145
|
+
method: 'POST',
|
|
3146
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
3147
|
+
body: buildClientCredentialsBody(creds),
|
|
3148
|
+
signal: AbortSignal.timeout(8000),
|
|
3149
|
+
});
|
|
3150
|
+
if (res.ok) {
|
|
3151
|
+
const tok = await res.json();
|
|
3152
|
+
if (tok.access_token) {
|
|
3153
|
+
JWT = tok.access_token;
|
|
3154
|
+
setEmbedJwt(tok.access_token);
|
|
3155
|
+
sendFunnelEvent('m2m_auth_completed', { grant: 'client_credentials', client_id: creds.clientId });
|
|
3156
|
+
process.stderr.write('🤖 cachly: authenticated via client_credentials (M2M, headless).\n');
|
|
3157
|
+
}
|
|
3158
|
+
}
|
|
3159
|
+
else {
|
|
3160
|
+
process.stderr.write(`⚠️ cachly: client_credentials auth failed (${res.status}). Check CACHLY_CLIENT_ID / CACHLY_CLIENT_SECRET.\n`);
|
|
3161
|
+
sendFunnelEvent('m2m_auth_failed', { status: res.status });
|
|
3162
|
+
}
|
|
3163
|
+
}
|
|
3164
|
+
catch (err) {
|
|
3165
|
+
process.stderr.write(`⚠️ cachly: client_credentials auth error: ${err.message}\n`);
|
|
3166
|
+
sendFunnelEvent('m2m_auth_failed', { reason: 'network' });
|
|
3167
|
+
}
|
|
3168
|
+
}
|
|
3169
|
+
}
|
|
3106
3170
|
// Credential-missing handling at startup. The critical distinction is HOW we were
|
|
3107
3171
|
// launched, because writing anything to stdout in stdio-MCP mode corrupts the
|
|
3108
3172
|
// JSON-RPC stream and exiting kills the zero-credential device-flow onboarding.
|
|
@@ -3110,7 +3174,7 @@ if (process.argv[2] === 'learn-git') {
|
|
|
3110
3174
|
// • Editor as an MCP stdio server (non-TTY) → ONE stderr hint, then KEEP RUNNING
|
|
3111
3175
|
// so tools/list works and the first tool call starts the browser sign-in.
|
|
3112
3176
|
// Skip entirely for CLI subcommands that intentionally run without credentials.
|
|
3113
|
-
const _cliNoAuthCommands = ['demo', 'share', 'publish', 'health', 'setup', 'init', 'digest', 'invite', 'badge', 'join', 'upgrade'];
|
|
3177
|
+
const _cliNoAuthCommands = ['demo', 'share', 'publish', 'health', 'setup', 'init', 'digest', 'invite', 'badge', 'join', 'upgrade', 'tool-specs', 'openapi'];
|
|
3114
3178
|
if (!JWT && !_cliNoAuthCommands.includes(process.argv[2] ?? '')) {
|
|
3115
3179
|
const runningInTerminal = !process.argv[2] && process.stdout.isTTY === true && _isMain;
|
|
3116
3180
|
if (runningInTerminal) {
|