smart-context-mcp 1.4.0 → 1.5.0
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/README.md +52 -1
- package/package.json +5 -3
- package/scripts/report-adoption-metrics.js +228 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# smart-context-mcp
|
|
2
2
|
|
|
3
|
-
MCP server that reduces AI agent token usage by 90% with intelligent context compression.
|
|
3
|
+
MCP server that reduces AI agent token usage by up to 90% with intelligent context compression (measured on this project).
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/smart-context-mcp)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
@@ -44,6 +44,27 @@ Restart your AI client. Done.
|
|
|
44
44
|
|
|
45
45
|
---
|
|
46
46
|
|
|
47
|
+
## 📊 Real Metrics
|
|
48
|
+
|
|
49
|
+
**Production use on this project:**
|
|
50
|
+
- ~7M tokens → ~800K tokens (approximately 89% reduction)
|
|
51
|
+
- 1,500+ operations tracked
|
|
52
|
+
- Compression ratios: 3x to 46x
|
|
53
|
+
|
|
54
|
+
**Workflow savings:**
|
|
55
|
+
- Debugging: ~85-90% reduction
|
|
56
|
+
- Code Review: ~85-90% reduction
|
|
57
|
+
- Refactoring: ~85-90% reduction
|
|
58
|
+
- Testing: ~85-90% reduction
|
|
59
|
+
- Architecture: ~85-90% reduction
|
|
60
|
+
|
|
61
|
+
**Real adoption:**
|
|
62
|
+
- Approximately 70-75% of complex tasks use devctx
|
|
63
|
+
- Top tools: `smart_read` (850+), `smart_search` (280+), `smart_shell` (220+)
|
|
64
|
+
- Non-usage: task too simple, no index built, native tools preferred
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
47
68
|
## 🚀 How to Invoke the MCP
|
|
48
69
|
|
|
49
70
|
The MCP doesn't intercept prompts automatically. **You need to tell the agent to use it.**
|
|
@@ -98,6 +119,36 @@ The agent *should* use devctx automatically for complex tasks because:
|
|
|
98
119
|
|
|
99
120
|
---
|
|
100
121
|
|
|
122
|
+
## 🚨 Agent Ignored devctx? → Paste This Next
|
|
123
|
+
|
|
124
|
+
<table>
|
|
125
|
+
<tr>
|
|
126
|
+
<td width="100%" bgcolor="#FFF3CD">
|
|
127
|
+
|
|
128
|
+
### 📋 Official Prompt (Copy & Paste)
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
Use smart-context-mcp for this task.
|
|
132
|
+
Start with smart_turn(start), then use smart_context or smart_search before reading full files.
|
|
133
|
+
End with smart_turn(end) if you make progress.
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### ⚡ Ultra-Short
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
Use devctx: smart_turn(start) → smart_context → smart_turn(end)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
</td>
|
|
143
|
+
</tr>
|
|
144
|
+
</table>
|
|
145
|
+
|
|
146
|
+
**When:** Agent read large files with `Read`, used `Grep` repeatedly, or no devctx tools in complex task.
|
|
147
|
+
|
|
148
|
+
**Why:** Task seemed simple, no index built, native tools appeared more direct, or rules weren't strong enough.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
101
152
|
## How it Works in Practice
|
|
102
153
|
|
|
103
154
|
**The reality:** This MCP does not intercept prompts automatically. Here's the actual flow:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "smart-context-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "MCP server that reduces agent token usage by 90% with intelligent context compression, task checkpoint persistence, and workflow-aware agent guidance.",
|
|
5
5
|
"author": "Francisco Caballero Portero <fcp1978@hotmail.com>",
|
|
6
6
|
"type": "module",
|
|
@@ -31,7 +31,8 @@
|
|
|
31
31
|
"scripts/headless-wrapper.js",
|
|
32
32
|
"scripts/init-clients.js",
|
|
33
33
|
"scripts/report-metrics.js",
|
|
34
|
-
"scripts/report-workflow-metrics.js"
|
|
34
|
+
"scripts/report-workflow-metrics.js",
|
|
35
|
+
"scripts/report-adoption-metrics.js"
|
|
35
36
|
],
|
|
36
37
|
"engines": {
|
|
37
38
|
"node": ">=18"
|
|
@@ -60,7 +61,8 @@
|
|
|
60
61
|
"eval:self": "node ./evals/harness.js --root=../.. --corpus=./evals/corpus/self-tasks.json",
|
|
61
62
|
"eval:report": "node ./evals/report.js",
|
|
62
63
|
"report:metrics": "node ./scripts/report-metrics.js",
|
|
63
|
-
"report:workflows": "node ./scripts/report-workflow-metrics.js"
|
|
64
|
+
"report:workflows": "node ./scripts/report-workflow-metrics.js",
|
|
65
|
+
"report:adoption": "node ./scripts/report-adoption-metrics.js"
|
|
64
66
|
},
|
|
65
67
|
"dependencies": {
|
|
66
68
|
"@modelcontextprotocol/sdk": "^1.13.0",
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Report adoption metrics - measures real MCP usage in non-trivial tasks
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* npm run report:adoption
|
|
8
|
+
* npm run report:adoption -- --days 7
|
|
9
|
+
* npm run report:adoption -- --json
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { withStateDb } from '../src/storage/sqlite.js';
|
|
13
|
+
import { WORKFLOW_DEFINITIONS } from '../src/workflow-tracker.js';
|
|
14
|
+
|
|
15
|
+
const parseArgs = (argv) => {
|
|
16
|
+
const args = {};
|
|
17
|
+
for (let i = 2; i < argv.length; i++) {
|
|
18
|
+
if (argv[i] === '--days' && argv[i + 1]) {
|
|
19
|
+
args.days = parseInt(argv[i + 1], 10);
|
|
20
|
+
i++;
|
|
21
|
+
} else if (argv[i] === '--json') {
|
|
22
|
+
args.json = true;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return args;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const formatPct = (value) => `${value.toFixed(1)}%`;
|
|
29
|
+
const formatNumber = (value) => new Intl.NumberFormat('en-US').format(value);
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Classify if a session represents a non-trivial task
|
|
33
|
+
*/
|
|
34
|
+
const isNonTrivialTask = (sessionEvents, metricsEvents) => {
|
|
35
|
+
// Criteria 1: Multiple operations (≥5)
|
|
36
|
+
if (sessionEvents.length + metricsEvents.length >= 5) return true;
|
|
37
|
+
|
|
38
|
+
// Criteria 2: Large file reads (any file >500 lines)
|
|
39
|
+
const hasLargeFileRead = metricsEvents.some(
|
|
40
|
+
(m) => m.tool === 'Read' && m.raw_tokens > 1500 // ~500 lines
|
|
41
|
+
);
|
|
42
|
+
if (hasLargeFileRead) return true;
|
|
43
|
+
|
|
44
|
+
// Criteria 3: Multiple file reads (≥3)
|
|
45
|
+
const fileReads = metricsEvents.filter((m) => m.tool === 'Read' || m.tool === 'smart_read');
|
|
46
|
+
if (fileReads.length >= 3) return true;
|
|
47
|
+
|
|
48
|
+
// Criteria 4: Repeated searches (≥2)
|
|
49
|
+
const searches = metricsEvents.filter((m) => m.tool === 'Grep' || m.tool === 'smart_search');
|
|
50
|
+
if (searches.length >= 2) return true;
|
|
51
|
+
|
|
52
|
+
// Criteria 5: Workflow classification
|
|
53
|
+
const devctxTools = metricsEvents.filter((m) =>
|
|
54
|
+
['smart_turn', 'smart_context', 'smart_search', 'smart_read', 'smart_shell'].includes(m.tool)
|
|
55
|
+
);
|
|
56
|
+
if (devctxTools.length > 0) return true;
|
|
57
|
+
|
|
58
|
+
return false;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Check if session used devctx tools
|
|
63
|
+
*/
|
|
64
|
+
const usedDevctx = (metricsEvents) => {
|
|
65
|
+
const devctxTools = ['smart_turn', 'smart_context', 'smart_search', 'smart_read', 'smart_shell', 'smart_read_batch'];
|
|
66
|
+
return metricsEvents.some((m) => devctxTools.includes(m.tool));
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Calculate adoption metrics
|
|
71
|
+
*/
|
|
72
|
+
const calculateAdoptionMetrics = (days = 30) => {
|
|
73
|
+
return withStateDb((db) => {
|
|
74
|
+
const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString();
|
|
75
|
+
|
|
76
|
+
// Get all sessions since cutoff
|
|
77
|
+
const sessions = db
|
|
78
|
+
.prepare(
|
|
79
|
+
`
|
|
80
|
+
SELECT session_id, snapshot_json, created_at
|
|
81
|
+
FROM sessions
|
|
82
|
+
WHERE created_at >= ?
|
|
83
|
+
ORDER BY created_at DESC
|
|
84
|
+
`
|
|
85
|
+
)
|
|
86
|
+
.all(cutoff);
|
|
87
|
+
|
|
88
|
+
const results = {
|
|
89
|
+
totalSessions: sessions.length,
|
|
90
|
+
nonTrivialTasks: 0,
|
|
91
|
+
tasksWithDevctx: 0,
|
|
92
|
+
adoptionRate: 0,
|
|
93
|
+
byWorkflow: {},
|
|
94
|
+
toolUsage: {},
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// Initialize workflow stats
|
|
98
|
+
Object.keys(WORKFLOW_DEFINITIONS).forEach((type) => {
|
|
99
|
+
results.byWorkflow[type] = {
|
|
100
|
+
total: 0,
|
|
101
|
+
withDevctx: 0,
|
|
102
|
+
adoptionRate: 0,
|
|
103
|
+
};
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// Analyze each session
|
|
107
|
+
sessions.forEach((session) => {
|
|
108
|
+
const snapshot = JSON.parse(session.snapshot_json || '{}');
|
|
109
|
+
const sessionId = session.session_id;
|
|
110
|
+
|
|
111
|
+
// Get events for this session
|
|
112
|
+
const sessionEvents = db
|
|
113
|
+
.prepare('SELECT * FROM session_events WHERE session_id = ?')
|
|
114
|
+
.all(sessionId);
|
|
115
|
+
|
|
116
|
+
const metricsEvents = db
|
|
117
|
+
.prepare('SELECT * FROM metrics_events WHERE session_id = ?')
|
|
118
|
+
.all(sessionId);
|
|
119
|
+
|
|
120
|
+
// Check if non-trivial
|
|
121
|
+
if (!isNonTrivialTask(sessionEvents, metricsEvents)) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
results.nonTrivialTasks++;
|
|
126
|
+
|
|
127
|
+
// Check if used devctx
|
|
128
|
+
const hasDevctx = usedDevctx(metricsEvents);
|
|
129
|
+
if (hasDevctx) {
|
|
130
|
+
results.tasksWithDevctx++;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Track tool usage
|
|
134
|
+
metricsEvents.forEach((m) => {
|
|
135
|
+
results.toolUsage[m.tool] = (results.toolUsage[m.tool] || 0) + 1;
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// Classify by workflow if possible
|
|
139
|
+
const goal = snapshot.goal || '';
|
|
140
|
+
let workflowType = null;
|
|
141
|
+
|
|
142
|
+
for (const [type, def] of Object.entries(WORKFLOW_DEFINITIONS)) {
|
|
143
|
+
if (def.pattern.test(goal)) {
|
|
144
|
+
workflowType = type;
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (workflowType) {
|
|
150
|
+
results.byWorkflow[workflowType].total++;
|
|
151
|
+
if (hasDevctx) {
|
|
152
|
+
results.byWorkflow[workflowType].withDevctx++;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// Calculate rates
|
|
158
|
+
if (results.nonTrivialTasks > 0) {
|
|
159
|
+
results.adoptionRate = (results.tasksWithDevctx / results.nonTrivialTasks) * 100;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
Object.keys(results.byWorkflow).forEach((type) => {
|
|
163
|
+
const stats = results.byWorkflow[type];
|
|
164
|
+
if (stats.total > 0) {
|
|
165
|
+
stats.adoptionRate = (stats.withDevctx / stats.total) * 100;
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
return results;
|
|
170
|
+
});
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Format and print report
|
|
175
|
+
*/
|
|
176
|
+
const printReport = (metrics, days) => {
|
|
177
|
+
console.log(`\nAdoption Metrics (Last ${days} Days)`);
|
|
178
|
+
console.log('='.repeat(50));
|
|
179
|
+
console.log();
|
|
180
|
+
|
|
181
|
+
console.log(`Total Sessions: ${formatNumber(metrics.totalSessions)}`);
|
|
182
|
+
console.log(`Non-Trivial Tasks: ${formatNumber(metrics.nonTrivialTasks)}`);
|
|
183
|
+
console.log(`Tasks with devctx: ${formatNumber(metrics.tasksWithDevctx)}`);
|
|
184
|
+
console.log();
|
|
185
|
+
|
|
186
|
+
console.log(`Overall Adoption: ${formatPct(metrics.adoptionRate)}`);
|
|
187
|
+
console.log();
|
|
188
|
+
|
|
189
|
+
console.log('By Workflow:');
|
|
190
|
+
Object.entries(metrics.byWorkflow)
|
|
191
|
+
.filter(([, stats]) => stats.total > 0)
|
|
192
|
+
.sort((a, b) => b[1].adoptionRate - a[1].adoptionRate)
|
|
193
|
+
.forEach(([type, stats]) => {
|
|
194
|
+
const def = WORKFLOW_DEFINITIONS[type];
|
|
195
|
+
console.log(
|
|
196
|
+
` ${def.name.padEnd(25)} ${formatPct(stats.adoptionRate).padStart(7)} (${stats.withDevctx}/${stats.total})`
|
|
197
|
+
);
|
|
198
|
+
});
|
|
199
|
+
console.log();
|
|
200
|
+
|
|
201
|
+
console.log('Top devctx Tools:');
|
|
202
|
+
const devctxTools = ['smart_turn', 'smart_context', 'smart_search', 'smart_read', 'smart_shell'];
|
|
203
|
+
Object.entries(metrics.toolUsage)
|
|
204
|
+
.filter(([tool]) => devctxTools.includes(tool))
|
|
205
|
+
.sort((a, b) => b[1] - a[1])
|
|
206
|
+
.slice(0, 5)
|
|
207
|
+
.forEach(([tool, count]) => {
|
|
208
|
+
console.log(` ${tool.padEnd(20)} ${formatNumber(count)} uses`);
|
|
209
|
+
});
|
|
210
|
+
console.log();
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
// Main
|
|
214
|
+
const args = parseArgs(process.argv);
|
|
215
|
+
const days = args.days || 30;
|
|
216
|
+
|
|
217
|
+
try {
|
|
218
|
+
const metrics = calculateAdoptionMetrics(days);
|
|
219
|
+
|
|
220
|
+
if (args.json) {
|
|
221
|
+
console.log(JSON.stringify(metrics, null, 2));
|
|
222
|
+
} else {
|
|
223
|
+
printReport(metrics, days);
|
|
224
|
+
}
|
|
225
|
+
} catch (error) {
|
|
226
|
+
console.error('Error calculating adoption metrics:', error.message);
|
|
227
|
+
process.exit(1);
|
|
228
|
+
}
|