toonify-mcp 0.1.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/LICENSE +21 -0
- package/README.md +344 -0
- package/README.zh-TW.md +324 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/metrics/metrics-collector.d.ts +40 -0
- package/dist/metrics/metrics-collector.d.ts.map +1 -0
- package/dist/metrics/metrics-collector.js +93 -0
- package/dist/metrics/metrics-collector.js.map +1 -0
- package/dist/optimizer/token-optimizer.d.ts +34 -0
- package/dist/optimizer/token-optimizer.d.ts.map +1 -0
- package/dist/optimizer/token-optimizer.js +186 -0
- package/dist/optimizer/token-optimizer.js.map +1 -0
- package/dist/optimizer/types.d.ts +42 -0
- package/dist/optimizer/types.d.ts.map +1 -0
- package/dist/optimizer/types.js +5 -0
- package/dist/optimizer/types.js.map +1 -0
- package/dist/server/mcp-server.d.ts +12 -0
- package/dist/server/mcp-server.d.ts.map +1 -0
- package/dist/server/mcp-server.js +111 -0
- package/dist/server/mcp-server.js.map +1 -0
- package/hooks/README.md +138 -0
- package/hooks/package.json +23 -0
- package/hooks/post-tool-use.js +161 -0
- package/hooks/post-tool-use.ts +201 -0
- package/hooks/tsconfig.json +18 -0
- package/jest.config.js +23 -0
- package/package.json +45 -0
- package/src/index.ts +23 -0
- package/src/metrics/metrics-collector.ts +125 -0
- package/src/optimizer/token-optimizer.ts +214 -0
- package/src/optimizer/types.ts +46 -0
- package/src/server/mcp-server.ts +134 -0
- package/test-mcp.json +5 -0
- package/tsconfig.json +20 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Claude Code Toonify MCP Server
|
|
4
|
+
*
|
|
5
|
+
* Optimizes token usage by converting structured data to TOON format
|
|
6
|
+
* before sending to Claude API, achieving 60%+ token reduction.
|
|
7
|
+
*/
|
|
8
|
+
import { ToonifyMCPServer } from './server/mcp-server.js';
|
|
9
|
+
async function main() {
|
|
10
|
+
const server = new ToonifyMCPServer();
|
|
11
|
+
try {
|
|
12
|
+
await server.start();
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
console.error('Failed to start Toonify MCP server:', error);
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
main();
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,IAAI,gBAAgB,EAAE,CAAC;IAEtC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,qCAAqC,EAAE,KAAK,CAAC,CAAC;QAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MetricsCollector: Local-only metrics tracking
|
|
3
|
+
*/
|
|
4
|
+
import type { TokenStats } from '../optimizer/types.js';
|
|
5
|
+
export interface OptimizationMetric {
|
|
6
|
+
timestamp: string;
|
|
7
|
+
toolName: string;
|
|
8
|
+
originalTokens: number;
|
|
9
|
+
optimizedTokens: number;
|
|
10
|
+
savings: number;
|
|
11
|
+
savingsPercentage: number;
|
|
12
|
+
wasOptimized: boolean;
|
|
13
|
+
format?: string;
|
|
14
|
+
reason?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare class MetricsCollector {
|
|
17
|
+
private statsPath;
|
|
18
|
+
constructor();
|
|
19
|
+
/**
|
|
20
|
+
* Record an optimization attempt
|
|
21
|
+
*/
|
|
22
|
+
record(metric: OptimizationMetric): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Get current statistics
|
|
25
|
+
*/
|
|
26
|
+
getStats(): Promise<TokenStats>;
|
|
27
|
+
/**
|
|
28
|
+
* Load stats from disk
|
|
29
|
+
*/
|
|
30
|
+
private loadStats;
|
|
31
|
+
/**
|
|
32
|
+
* Save stats to disk
|
|
33
|
+
*/
|
|
34
|
+
private saveStats;
|
|
35
|
+
/**
|
|
36
|
+
* Format stats as dashboard
|
|
37
|
+
*/
|
|
38
|
+
formatDashboard(): Promise<string>;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=metrics-collector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics-collector.d.ts","sourceRoot":"","sources":["../../src/metrics/metrics-collector.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAExD,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,SAAS,CAAS;;IAW1B;;OAEG;IACG,MAAM,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IA2BvD;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,UAAU,CAAC;IAIrC;;OAEG;YACW,SAAS;IAoBvB;;OAEG;YACW,SAAS;IAQvB;;OAEG;IACG,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC;CAiBzC"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MetricsCollector: Local-only metrics tracking
|
|
3
|
+
*/
|
|
4
|
+
import { promises as fs } from 'fs';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import os from 'os';
|
|
7
|
+
export class MetricsCollector {
|
|
8
|
+
statsPath;
|
|
9
|
+
constructor() {
|
|
10
|
+
// Store in user's home directory, not in project
|
|
11
|
+
this.statsPath = path.join(os.homedir(), '.claude', 'token_stats.json');
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Record an optimization attempt
|
|
15
|
+
*/
|
|
16
|
+
async record(metric) {
|
|
17
|
+
try {
|
|
18
|
+
const stats = await this.loadStats();
|
|
19
|
+
// Update aggregated stats
|
|
20
|
+
stats.totalRequests++;
|
|
21
|
+
if (metric.wasOptimized) {
|
|
22
|
+
stats.optimizedRequests++;
|
|
23
|
+
}
|
|
24
|
+
stats.tokensBeforeOptimization += metric.originalTokens;
|
|
25
|
+
stats.tokensAfterOptimization += metric.optimizedTokens;
|
|
26
|
+
stats.totalSavings += metric.savings;
|
|
27
|
+
// Recalculate average
|
|
28
|
+
stats.averageSavingsPercentage =
|
|
29
|
+
stats.optimizedRequests > 0
|
|
30
|
+
? (stats.totalSavings / stats.tokensBeforeOptimization) * 100
|
|
31
|
+
: 0;
|
|
32
|
+
await this.saveStats(stats);
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
// Silent failure - metrics should never break functionality
|
|
36
|
+
console.error('Failed to record metrics:', error);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Get current statistics
|
|
41
|
+
*/
|
|
42
|
+
async getStats() {
|
|
43
|
+
return await this.loadStats();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Load stats from disk
|
|
47
|
+
*/
|
|
48
|
+
async loadStats() {
|
|
49
|
+
try {
|
|
50
|
+
// Ensure directory exists
|
|
51
|
+
await fs.mkdir(path.dirname(this.statsPath), { recursive: true });
|
|
52
|
+
const data = await fs.readFile(this.statsPath, 'utf-8');
|
|
53
|
+
return JSON.parse(data);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// Return empty stats if file doesn't exist
|
|
57
|
+
return {
|
|
58
|
+
totalRequests: 0,
|
|
59
|
+
optimizedRequests: 0,
|
|
60
|
+
tokensBeforeOptimization: 0,
|
|
61
|
+
tokensAfterOptimization: 0,
|
|
62
|
+
totalSavings: 0,
|
|
63
|
+
averageSavingsPercentage: 0,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Save stats to disk
|
|
69
|
+
*/
|
|
70
|
+
async saveStats(stats) {
|
|
71
|
+
await fs.writeFile(this.statsPath, JSON.stringify(stats, null, 2), 'utf-8');
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Format stats as dashboard
|
|
75
|
+
*/
|
|
76
|
+
async formatDashboard() {
|
|
77
|
+
const stats = await this.getStats();
|
|
78
|
+
return `
|
|
79
|
+
📊 Token Optimization Stats
|
|
80
|
+
━━━━━━━━━━━━━━━━━━━━━━━━
|
|
81
|
+
Total Requests: ${stats.totalRequests}
|
|
82
|
+
Optimized: ${stats.optimizedRequests} (${((stats.optimizedRequests / stats.totalRequests) * 100).toFixed(1)}%)
|
|
83
|
+
|
|
84
|
+
Tokens Before: ${stats.tokensBeforeOptimization.toLocaleString()}
|
|
85
|
+
Tokens After: ${stats.tokensAfterOptimization.toLocaleString()}
|
|
86
|
+
Total Savings: ${stats.totalSavings.toLocaleString()} (${stats.averageSavingsPercentage.toFixed(1)}%)
|
|
87
|
+
|
|
88
|
+
💰 Cost Savings (at $3/1M input tokens):
|
|
89
|
+
$${((stats.totalSavings / 1_000_000) * 3).toFixed(2)} saved
|
|
90
|
+
`.trim();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=metrics-collector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics-collector.js","sourceRoot":"","sources":["../../src/metrics/metrics-collector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TokenOptimizer: Core optimization logic using Toonify
|
|
3
|
+
*/
|
|
4
|
+
import type { OptimizationResult, ToolMetadata, OptimizationConfig } from './types.js';
|
|
5
|
+
export declare class TokenOptimizer {
|
|
6
|
+
private config;
|
|
7
|
+
private tokenEncoder;
|
|
8
|
+
constructor(config?: Partial<OptimizationConfig>);
|
|
9
|
+
/**
|
|
10
|
+
* Main optimization method
|
|
11
|
+
*/
|
|
12
|
+
optimize(content: string, metadata?: ToolMetadata): Promise<OptimizationResult>;
|
|
13
|
+
/**
|
|
14
|
+
* Detect if content is structured data (JSON/CSV/YAML)
|
|
15
|
+
*/
|
|
16
|
+
private detectStructuredData;
|
|
17
|
+
/**
|
|
18
|
+
* Simple CSV detection heuristic
|
|
19
|
+
*/
|
|
20
|
+
private looksLikeCSV;
|
|
21
|
+
/**
|
|
22
|
+
* Parse simple CSV to array of objects
|
|
23
|
+
*/
|
|
24
|
+
private parseSimpleCSV;
|
|
25
|
+
/**
|
|
26
|
+
* Count tokens in text
|
|
27
|
+
*/
|
|
28
|
+
private countTokens;
|
|
29
|
+
/**
|
|
30
|
+
* Check if tool should be skipped
|
|
31
|
+
*/
|
|
32
|
+
private shouldSkipTool;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=token-optimizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-optimizer.d.ts","sourceRoot":"","sources":["../../src/optimizer/token-optimizer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EACV,kBAAkB,EAClB,YAAY,EAEZ,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAEpB,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,YAAY,CAAC;gBAET,MAAM,GAAE,OAAO,CAAC,kBAAkB,CAAM;IAcpD;;OAEG;IACG,QAAQ,CACZ,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,YAAY,GACtB,OAAO,CAAC,kBAAkB,CAAC;IA2F9B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IA4B5B;;OAEG;IACH,OAAO,CAAC,YAAY;IAiBpB;;OAEG;IACH,OAAO,CAAC,cAAc;IActB;;OAEG;IACH,OAAO,CAAC,WAAW;IAInB;;OAEG;IACH,OAAO,CAAC,cAAc;CAMvB"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TokenOptimizer: Core optimization logic using Toonify
|
|
3
|
+
*/
|
|
4
|
+
import { encode as toonEncode } from '@toon-format/toon';
|
|
5
|
+
import { encoding_for_model } from 'tiktoken';
|
|
6
|
+
import yaml from 'yaml';
|
|
7
|
+
export class TokenOptimizer {
|
|
8
|
+
config;
|
|
9
|
+
tokenEncoder;
|
|
10
|
+
constructor(config = {}) {
|
|
11
|
+
this.config = {
|
|
12
|
+
enabled: true,
|
|
13
|
+
minTokensThreshold: 50,
|
|
14
|
+
minSavingsThreshold: 30,
|
|
15
|
+
maxProcessingTime: 50,
|
|
16
|
+
skipToolPatterns: [],
|
|
17
|
+
...config
|
|
18
|
+
};
|
|
19
|
+
// Use Claude tokenizer
|
|
20
|
+
this.tokenEncoder = encoding_for_model('gpt-4');
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Main optimization method
|
|
24
|
+
*/
|
|
25
|
+
async optimize(content, metadata) {
|
|
26
|
+
const startTime = Date.now();
|
|
27
|
+
// Quick path: skip if disabled or content too small
|
|
28
|
+
if (!this.config.enabled || content.length < 200) {
|
|
29
|
+
return {
|
|
30
|
+
optimized: false,
|
|
31
|
+
originalContent: content,
|
|
32
|
+
originalTokens: this.countTokens(content),
|
|
33
|
+
reason: 'Content too small'
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
// Skip if tool matches skip patterns
|
|
37
|
+
if (metadata?.toolName && this.shouldSkipTool(metadata.toolName)) {
|
|
38
|
+
return {
|
|
39
|
+
optimized: false,
|
|
40
|
+
originalContent: content,
|
|
41
|
+
originalTokens: this.countTokens(content),
|
|
42
|
+
reason: `Tool ${metadata.toolName} in skip list`
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
// Detect structured data
|
|
46
|
+
const structuredData = this.detectStructuredData(content);
|
|
47
|
+
if (!structuredData) {
|
|
48
|
+
return {
|
|
49
|
+
optimized: false,
|
|
50
|
+
originalContent: content,
|
|
51
|
+
originalTokens: this.countTokens(content),
|
|
52
|
+
reason: 'Not structured data'
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
// Convert to TOON format
|
|
57
|
+
const toonContent = toonEncode(structuredData.data);
|
|
58
|
+
// Count tokens
|
|
59
|
+
const originalTokens = this.countTokens(content);
|
|
60
|
+
const optimizedTokens = this.countTokens(toonContent);
|
|
61
|
+
// Calculate savings
|
|
62
|
+
const tokenSavings = originalTokens - optimizedTokens;
|
|
63
|
+
const savingsPercentage = (tokenSavings / originalTokens) * 100;
|
|
64
|
+
// Check if worth using
|
|
65
|
+
if (savingsPercentage < this.config.minSavingsThreshold) {
|
|
66
|
+
return {
|
|
67
|
+
optimized: false,
|
|
68
|
+
originalContent: content,
|
|
69
|
+
originalTokens,
|
|
70
|
+
reason: `Savings too low: ${savingsPercentage.toFixed(1)}%`
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
// Check processing time
|
|
74
|
+
const elapsed = Date.now() - startTime;
|
|
75
|
+
if (elapsed > this.config.maxProcessingTime) {
|
|
76
|
+
return {
|
|
77
|
+
optimized: false,
|
|
78
|
+
originalContent: content,
|
|
79
|
+
originalTokens,
|
|
80
|
+
reason: `Processing timeout: ${elapsed}ms`
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
optimized: true,
|
|
85
|
+
originalContent: content,
|
|
86
|
+
optimizedContent: toonContent,
|
|
87
|
+
originalTokens,
|
|
88
|
+
optimizedTokens,
|
|
89
|
+
savings: {
|
|
90
|
+
tokens: tokenSavings,
|
|
91
|
+
percentage: savingsPercentage
|
|
92
|
+
},
|
|
93
|
+
format: structuredData.type
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
// Silent fallback on error
|
|
98
|
+
return {
|
|
99
|
+
optimized: false,
|
|
100
|
+
originalContent: content,
|
|
101
|
+
originalTokens: this.countTokens(content),
|
|
102
|
+
reason: `Error: ${error instanceof Error ? error.message : 'Unknown'}`
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Detect if content is structured data (JSON/CSV/YAML)
|
|
108
|
+
*/
|
|
109
|
+
detectStructuredData(content) {
|
|
110
|
+
// Try JSON first
|
|
111
|
+
try {
|
|
112
|
+
const data = JSON.parse(content);
|
|
113
|
+
if (typeof data === 'object' && data !== null) {
|
|
114
|
+
return { type: 'json', data, confidence: 1.0 };
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch { }
|
|
118
|
+
// Try YAML
|
|
119
|
+
try {
|
|
120
|
+
const data = yaml.parse(content);
|
|
121
|
+
if (typeof data === 'object' && data !== null) {
|
|
122
|
+
return { type: 'yaml', data, confidence: 0.9 };
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
catch { }
|
|
126
|
+
// Try CSV (simple heuristic)
|
|
127
|
+
if (this.looksLikeCSV(content)) {
|
|
128
|
+
try {
|
|
129
|
+
const data = this.parseSimpleCSV(content);
|
|
130
|
+
return { type: 'csv', data, confidence: 0.8 };
|
|
131
|
+
}
|
|
132
|
+
catch { }
|
|
133
|
+
}
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Simple CSV detection heuristic
|
|
138
|
+
*/
|
|
139
|
+
looksLikeCSV(content) {
|
|
140
|
+
const lines = content.split('\n').filter(l => l.trim());
|
|
141
|
+
if (lines.length < 2)
|
|
142
|
+
return false;
|
|
143
|
+
const firstLineCommas = (lines[0].match(/,/g) || []).length;
|
|
144
|
+
if (firstLineCommas === 0)
|
|
145
|
+
return false;
|
|
146
|
+
// Check if most lines have similar comma count
|
|
147
|
+
let matchingLines = 0;
|
|
148
|
+
for (let i = 1; i < Math.min(lines.length, 10); i++) {
|
|
149
|
+
const commas = (lines[i].match(/,/g) || []).length;
|
|
150
|
+
if (commas === firstLineCommas)
|
|
151
|
+
matchingLines++;
|
|
152
|
+
}
|
|
153
|
+
return matchingLines >= Math.min(lines.length - 1, 7);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Parse simple CSV to array of objects
|
|
157
|
+
*/
|
|
158
|
+
parseSimpleCSV(content) {
|
|
159
|
+
const lines = content.split('\n').filter(l => l.trim());
|
|
160
|
+
const headers = lines[0].split(',').map(h => h.trim());
|
|
161
|
+
return lines.slice(1).map(line => {
|
|
162
|
+
const values = line.split(',').map(v => v.trim());
|
|
163
|
+
const obj = {};
|
|
164
|
+
headers.forEach((header, i) => {
|
|
165
|
+
obj[header] = values[i] || '';
|
|
166
|
+
});
|
|
167
|
+
return obj;
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Count tokens in text
|
|
172
|
+
*/
|
|
173
|
+
countTokens(text) {
|
|
174
|
+
return this.tokenEncoder.encode(text).length;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Check if tool should be skipped
|
|
178
|
+
*/
|
|
179
|
+
shouldSkipTool(toolName) {
|
|
180
|
+
return this.config.skipToolPatterns?.some(pattern => {
|
|
181
|
+
const regex = new RegExp(pattern);
|
|
182
|
+
return regex.test(toolName);
|
|
183
|
+
}) ?? false;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=token-optimizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-optimizer.js","sourceRoot":"","sources":["../../src/optimizer/token-optimizer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for token optimization
|
|
3
|
+
*/
|
|
4
|
+
export interface OptimizationResult {
|
|
5
|
+
optimized: boolean;
|
|
6
|
+
originalContent: string;
|
|
7
|
+
optimizedContent?: string;
|
|
8
|
+
originalTokens: number;
|
|
9
|
+
optimizedTokens?: number;
|
|
10
|
+
savings?: {
|
|
11
|
+
tokens: number;
|
|
12
|
+
percentage: number;
|
|
13
|
+
};
|
|
14
|
+
format?: 'json' | 'csv' | 'yaml' | 'unknown';
|
|
15
|
+
reason?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ToolMetadata {
|
|
18
|
+
toolName: string;
|
|
19
|
+
contentType?: string;
|
|
20
|
+
size: number;
|
|
21
|
+
}
|
|
22
|
+
export interface StructuredData {
|
|
23
|
+
type: 'json' | 'csv' | 'yaml';
|
|
24
|
+
data: any;
|
|
25
|
+
confidence: number;
|
|
26
|
+
}
|
|
27
|
+
export interface OptimizationConfig {
|
|
28
|
+
enabled: boolean;
|
|
29
|
+
minTokensThreshold: number;
|
|
30
|
+
minSavingsThreshold: number;
|
|
31
|
+
maxProcessingTime: number;
|
|
32
|
+
skipToolPatterns?: string[];
|
|
33
|
+
}
|
|
34
|
+
export interface TokenStats {
|
|
35
|
+
totalRequests: number;
|
|
36
|
+
optimizedRequests: number;
|
|
37
|
+
tokensBeforeOptimization: number;
|
|
38
|
+
tokensAfterOptimization: number;
|
|
39
|
+
totalSavings: number;
|
|
40
|
+
averageSavingsPercentage: number;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/optimizer/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE;QACR,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,SAAS,CAAC;IAC7C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;IAC9B,IAAI,EAAE,GAAG,CAAC;IACV,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,UAAU;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,wBAAwB,EAAE,MAAM,CAAC;IACjC,uBAAuB,EAAE,MAAM,CAAC;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,wBAAwB,EAAE,MAAM,CAAC;CAClC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/optimizer/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ToonifyMCPServer: MCP server that wraps tool results with token optimization
|
|
3
|
+
*/
|
|
4
|
+
export declare class ToonifyMCPServer {
|
|
5
|
+
private server;
|
|
6
|
+
private optimizer;
|
|
7
|
+
private metrics;
|
|
8
|
+
constructor();
|
|
9
|
+
private setupHandlers;
|
|
10
|
+
start(): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=mcp-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../../src/server/mcp-server.ts"],"names":[],"mappings":"AAAA;;GAEG;AAWH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,OAAO,CAAmB;;IAqBlC,OAAO,CAAC,aAAa;IA0Ff,KAAK;CAMZ"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ToonifyMCPServer: MCP server that wraps tool results with token optimization
|
|
3
|
+
*/
|
|
4
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
5
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
6
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
7
|
+
import { TokenOptimizer } from '../optimizer/token-optimizer.js';
|
|
8
|
+
import { MetricsCollector } from '../metrics/metrics-collector.js';
|
|
9
|
+
export class ToonifyMCPServer {
|
|
10
|
+
server;
|
|
11
|
+
optimizer;
|
|
12
|
+
metrics;
|
|
13
|
+
constructor() {
|
|
14
|
+
this.server = new Server({
|
|
15
|
+
name: 'claude-code-toonify',
|
|
16
|
+
version: '0.1.0',
|
|
17
|
+
}, {
|
|
18
|
+
capabilities: {
|
|
19
|
+
tools: {},
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
this.optimizer = new TokenOptimizer();
|
|
23
|
+
this.metrics = new MetricsCollector();
|
|
24
|
+
this.setupHandlers();
|
|
25
|
+
}
|
|
26
|
+
setupHandlers() {
|
|
27
|
+
// List available tools
|
|
28
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
29
|
+
tools: [
|
|
30
|
+
{
|
|
31
|
+
name: 'optimize_content',
|
|
32
|
+
description: 'Optimize structured data content for token efficiency using TOON format',
|
|
33
|
+
inputSchema: {
|
|
34
|
+
type: 'object',
|
|
35
|
+
properties: {
|
|
36
|
+
content: {
|
|
37
|
+
type: 'string',
|
|
38
|
+
description: 'The content to optimize (JSON, CSV, or YAML)',
|
|
39
|
+
},
|
|
40
|
+
toolName: {
|
|
41
|
+
type: 'string',
|
|
42
|
+
description: 'Name of the tool that generated this content',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
required: ['content'],
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: 'get_stats',
|
|
50
|
+
description: 'Get token optimization statistics',
|
|
51
|
+
inputSchema: {
|
|
52
|
+
type: 'object',
|
|
53
|
+
properties: {},
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
}));
|
|
58
|
+
// Handle tool calls
|
|
59
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
60
|
+
const { name, arguments: args } = request.params;
|
|
61
|
+
switch (name) {
|
|
62
|
+
case 'optimize_content': {
|
|
63
|
+
const { content, toolName } = args;
|
|
64
|
+
const result = await this.optimizer.optimize(content, {
|
|
65
|
+
toolName: toolName || 'unknown',
|
|
66
|
+
size: content.length,
|
|
67
|
+
});
|
|
68
|
+
// Record metrics
|
|
69
|
+
await this.metrics.record({
|
|
70
|
+
timestamp: new Date().toISOString(),
|
|
71
|
+
toolName: toolName || 'unknown',
|
|
72
|
+
originalTokens: result.originalTokens,
|
|
73
|
+
optimizedTokens: result.optimizedTokens || result.originalTokens,
|
|
74
|
+
savings: result.savings?.tokens || 0,
|
|
75
|
+
savingsPercentage: result.savings?.percentage || 0,
|
|
76
|
+
wasOptimized: result.optimized,
|
|
77
|
+
format: result.format,
|
|
78
|
+
reason: result.reason,
|
|
79
|
+
});
|
|
80
|
+
return {
|
|
81
|
+
content: [
|
|
82
|
+
{
|
|
83
|
+
type: 'text',
|
|
84
|
+
text: JSON.stringify(result, null, 2),
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
case 'get_stats': {
|
|
90
|
+
const stats = await this.metrics.getStats();
|
|
91
|
+
return {
|
|
92
|
+
content: [
|
|
93
|
+
{
|
|
94
|
+
type: 'text',
|
|
95
|
+
text: JSON.stringify(stats, null, 2),
|
|
96
|
+
},
|
|
97
|
+
],
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
default:
|
|
101
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
async start() {
|
|
106
|
+
const transport = new StdioServerTransport();
|
|
107
|
+
await this.server.connect(transport);
|
|
108
|
+
console.error('Toonify MCP Server running on stdio');
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=mcp-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../../src/server/mcp-server.ts"],"names":[],"mappings":"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"}
|