local-model-suitability-mcp 1.1.22 → 1.1.23
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/CHANGELOG.md +5 -0
- package/package.json +1 -1
- package/server.json +36 -36
- package/src/server.js +13 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.1.23] - 2026-06-25
|
|
4
|
+
- feat: calls_remaining field added to check_local_viability response -- "unlimited" for paid keys, numeric free-tier headroom otherwise (HTTP POST and stdio transports)
|
|
5
|
+
- feat: verdict_ttl field added (86400s/24h)
|
|
6
|
+
- feat: data_source_status field added (full/degraded) -- "degraded" when Anthropic responds but returns unparseable output and a fallback verdict is used; "full" otherwise, including the CONFIDENTIAL local-rule shortcut which never calls Anthropic
|
|
7
|
+
|
|
3
8
|
## [1.1.22] - 2026-06-24
|
|
4
9
|
- feat: unauthenticated /public-stats endpoint -- first_deployed, lifetime tool calls, uptime %, version, for agent orchestrators evaluating server trustworthiness
|
|
5
10
|
- feat: /process-trial-followups endpoint + 24h follow-up record on trial-extension grant
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "local-model-suitability-mcp",
|
|
3
3
|
"mcpName": "io.github.OjasKord/local-model-suitability-mcp",
|
|
4
|
-
"version": "1.1.
|
|
4
|
+
"version": "1.1.23",
|
|
5
5
|
"description": "AI model router for agents. Checks whether a local model can handle the task before calling cloud inference. LOCAL/CLOUD verdict saves cost on every call.",
|
|
6
6
|
"main": "src/server.js",
|
|
7
7
|
"type": "module",
|
package/server.json
CHANGED
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
|
-
"name": "io.github.OjasKord/local-model-suitability-mcp",
|
|
4
|
-
"title": "Local Model Suitability MCP",
|
|
5
|
-
"description": "Check if a task runs locally vs cloud. Save money on calls that don't need cloud inference.",
|
|
6
|
-
"version": "1.1.
|
|
7
|
-
"websiteUrl": "https://kordagencies.com",
|
|
8
|
-
"repository": {
|
|
9
|
-
"url": "https://github.com/OjasKord/local-model-suitability-mcp",
|
|
10
|
-
"source": "github"
|
|
11
|
-
},
|
|
12
|
-
"packages": [
|
|
13
|
-
{
|
|
14
|
-
"registryType": "npm",
|
|
15
|
-
"identifier": "local-model-suitability-mcp",
|
|
16
|
-
"version": "1.1.
|
|
17
|
-
"transport": {
|
|
18
|
-
"type": "stdio"
|
|
19
|
-
},
|
|
20
|
-
"environmentVariables": [
|
|
21
|
-
{
|
|
22
|
-
"name": "ANTHROPIC_API_KEY",
|
|
23
|
-
"description": "Anthropic API key for Claude routing analysis",
|
|
24
|
-
"isRequired": true,
|
|
25
|
-
"isSecret": true
|
|
26
|
-
}
|
|
27
|
-
]
|
|
28
|
-
}
|
|
29
|
-
],
|
|
30
|
-
"remotes": [
|
|
31
|
-
{
|
|
32
|
-
"type": "streamable-http",
|
|
33
|
-
"url": "https://local-model-suitability-mcp-production.up.railway.app"
|
|
34
|
-
}
|
|
35
|
-
]
|
|
36
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
|
+
"name": "io.github.OjasKord/local-model-suitability-mcp",
|
|
4
|
+
"title": "Local Model Suitability MCP",
|
|
5
|
+
"description": "Check if a task runs locally vs cloud. Save money on calls that don't need cloud inference.",
|
|
6
|
+
"version": "1.1.23",
|
|
7
|
+
"websiteUrl": "https://kordagencies.com",
|
|
8
|
+
"repository": {
|
|
9
|
+
"url": "https://github.com/OjasKord/local-model-suitability-mcp",
|
|
10
|
+
"source": "github"
|
|
11
|
+
},
|
|
12
|
+
"packages": [
|
|
13
|
+
{
|
|
14
|
+
"registryType": "npm",
|
|
15
|
+
"identifier": "local-model-suitability-mcp",
|
|
16
|
+
"version": "1.1.23",
|
|
17
|
+
"transport": {
|
|
18
|
+
"type": "stdio"
|
|
19
|
+
},
|
|
20
|
+
"environmentVariables": [
|
|
21
|
+
{
|
|
22
|
+
"name": "ANTHROPIC_API_KEY",
|
|
23
|
+
"description": "Anthropic API key for Claude routing analysis",
|
|
24
|
+
"isRequired": true,
|
|
25
|
+
"isSecret": true
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"remotes": [
|
|
31
|
+
{
|
|
32
|
+
"type": "streamable-http",
|
|
33
|
+
"url": "https://local-model-suitability-mcp-production.up.railway.app"
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
}
|
package/src/server.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createHmac, timingSafeEqual } from 'crypto';
|
|
|
3
3
|
import { readFileSync, writeFileSync } from 'fs';
|
|
4
4
|
import Anthropic from '@anthropic-ai/sdk';
|
|
5
5
|
|
|
6
|
-
const VERSION = '1.1.
|
|
6
|
+
const VERSION = '1.1.23';
|
|
7
7
|
const FIRST_DEPLOYED = '2026-04-13T06:41:38Z';
|
|
8
8
|
const LIFETIME_CALLS_REDIS_KEY = 'lms:lifetime_calls';
|
|
9
9
|
const UPTIME_HEARTBEAT_KEY = 'lms:uptime:heartbeat_count';
|
|
@@ -16,6 +16,8 @@ const ENTERPRISE_UPGRADE_URL = 'https://buy.stripe.com/28E9AS27PbPvfkoe7Sebu0q';
|
|
|
16
16
|
const ALLOWED_PAYMENT_LINK_IDS = ['plink_1TQzCBD6WvRe6sn3H1q5t2LF', 'plink_1TQzDSD6WvRe6sn3UM2G1EgX'];
|
|
17
17
|
const PERSIST_FILE = '/tmp/lms_stats.json';
|
|
18
18
|
const LEGAL_DISCLAIMER = 'AI-powered routing analysis. We do not log or store your task content. Results are for cost-optimisation guidance only. Provider maximum liability is limited to subscription fees paid in the preceding 3 months. Full terms: kordagencies.com/terms.html';
|
|
19
|
+
// Caching/staleness policy per tool, in seconds.
|
|
20
|
+
const VERDICT_TTL = { check_local_viability: 86400 };
|
|
19
21
|
|
|
20
22
|
function nowISO() { return new Date().toISOString(); }
|
|
21
23
|
|
|
@@ -382,6 +384,8 @@ async function checkLocalViability(task, qualityThreshold, dataSensitivity) {
|
|
|
382
384
|
cloud_justified_reason: null,
|
|
383
385
|
data_sensitivity_override: true,
|
|
384
386
|
analysis_type: 'AI-powered cost routing — NOT a simple lookup',
|
|
387
|
+
verdict_ttl: VERDICT_TTL.check_local_viability,
|
|
388
|
+
data_source_status: 'full',
|
|
385
389
|
_disclaimer: LEGAL_DISCLAIMER
|
|
386
390
|
};
|
|
387
391
|
}
|
|
@@ -429,6 +433,7 @@ Respond ONLY with a JSON object — no markdown, no explanation outside the JSON
|
|
|
429
433
|
|
|
430
434
|
const raw = response.content[0].text.trim();
|
|
431
435
|
let parsed;
|
|
436
|
+
let aiDegraded = false;
|
|
432
437
|
try {
|
|
433
438
|
parsed = JSON.parse(raw);
|
|
434
439
|
} catch(e) {
|
|
@@ -441,6 +446,7 @@ Respond ONLY with a JSON object — no markdown, no explanation outside the JSON
|
|
|
441
446
|
recommended_local_models: ['llama3.2:8b', 'mistral-7b'],
|
|
442
447
|
cloud_justified_reason: null
|
|
443
448
|
};
|
|
449
|
+
aiDegraded = true;
|
|
444
450
|
}
|
|
445
451
|
|
|
446
452
|
const _rLms = {
|
|
@@ -448,6 +454,8 @@ Respond ONLY with a JSON object — no markdown, no explanation outside the JSON
|
|
|
448
454
|
task_quality_threshold: quality,
|
|
449
455
|
data_sensitivity: sensitivity,
|
|
450
456
|
analysis_type: 'AI-powered cost routing — NOT a simple lookup',
|
|
457
|
+
verdict_ttl: VERDICT_TTL.check_local_viability,
|
|
458
|
+
data_source_status: aiDegraded ? 'degraded' : 'full',
|
|
451
459
|
checked_at: nowISO(),
|
|
452
460
|
_disclaimer: LEGAL_DISCLAIMER
|
|
453
461
|
};
|
|
@@ -890,9 +898,11 @@ const server = createServer(async (req, res) => {
|
|
|
890
898
|
redisIncr(LIFETIME_CALLS_REDIS_KEY).catch(() => {});
|
|
891
899
|
logCall('check_local_viability', access.tier, clientIp);
|
|
892
900
|
appendSessionLog(clientIp, 'check_local_viability').catch((e) => console.error('[SessionLog] appendSessionLog failed:', e));
|
|
901
|
+
const callsRemaining = access.tier === 'free' ? Math.max(0, FREE_TIER_LIMIT - getFreeTierCount(clientIp)) : 'unlimited';
|
|
893
902
|
|
|
894
903
|
try {
|
|
895
904
|
const result = await checkLocalViability(task, quality_threshold, data_sensitivity);
|
|
905
|
+
result.calls_remaining = callsRemaining;
|
|
896
906
|
|
|
897
907
|
// Partial response for free tier
|
|
898
908
|
if (access.tier === 'free') {
|
|
@@ -902,6 +912,7 @@ const server = createServer(async (req, res) => {
|
|
|
902
912
|
reason: result.reason,
|
|
903
913
|
analysis_type: result.analysis_type,
|
|
904
914
|
checked_at: result.checked_at,
|
|
915
|
+
calls_remaining: result.calls_remaining,
|
|
905
916
|
_disclaimer: result._disclaimer,
|
|
906
917
|
upgrade_url: PRO_UPGRADE_URL
|
|
907
918
|
};
|
|
@@ -977,6 +988,7 @@ function setupStdio() {
|
|
|
977
988
|
} else {
|
|
978
989
|
try {
|
|
979
990
|
const result = await checkLocalViability(task, quality_threshold, data_sensitivity);
|
|
991
|
+
result.calls_remaining = 'unlimited';
|
|
980
992
|
response = { jsonrpc: '2.0', id: req.id, result: { content: [{ type: 'text', text: JSON.stringify(result) }] } };
|
|
981
993
|
} catch(e) {
|
|
982
994
|
response = { jsonrpc: '2.0', id: req.id, result: { content: [{ type: 'text', text: JSON.stringify({ error: e.message, likely_cause: 'AI routing analysis failed — transient Anthropic API issue', retryable: true, retry_after_ms: 120000, fallback_tool: null, agent_action: 'RETRY_IN_2_MIN', category: 'ai_failure', trace_id: nowISO(), _disclaimer: LEGAL_DISCLAIMER }) }] } };
|