@semanticintent/semantic-chirp-intelligence-mcp 3.0.0 → 4.0.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/.chirp-data/opponent.json +24 -0
- package/.chirp-data/roster.json +34 -0
- package/.chirp-data/standings.json +17 -0
- package/.nhl-schedule-cache/20262027.json +1 -0
- package/.nhl-schedule-cache/players-20262027-20252026.json +1 -0
- package/README.md +129 -79
- package/build/analyses/BreakoutAnalysis.js +25 -36
- package/build/analyses/DraftPickAnalysis.js +431 -0
- package/build/analyses/GamesInHandAnalysis.js +52 -121
- package/build/analyses/IceAnalysis.js +66 -57
- package/build/analyses/LineupAnalysis.js +26 -46
- package/build/analyses/ScheduleValueAnalysis.js +279 -0
- package/build/analyses/StreamingAnalysis.js +40 -76
- package/build/analyses/WeekendStreamAnalysis.js +130 -66
- package/build/config/tool-metadata.js +68 -0
- package/build/domain/nhl-teams.js +67 -0
- package/build/index.js +619 -495
- package/build/services/LeagueDataService.js +130 -0
- package/build/services/NhlScheduleService.js +357 -0
- package/build/services/NhlStatsService.js +297 -0
- package/build/services/RosterStore.js +233 -0
- package/package.json +16 -17
- package/scripts/preflight.mjs +67 -0
- package/scripts/smoke.mjs +92 -0
- package/.env.example +0 -8
- package/authenticate.js +0 -207
- package/build/experimental/semantic-breakout-tool.js +0 -188
- package/build/experimental/semantic-intent-parser.js +0 -222
- package/build/experimental/semantic-tool-integration.js +0 -146
- package/build/experimental/test-parser.js +0 -61
- package/build/services/YahooApiClient.js +0 -309
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* 💨 Smoke test — call every registered tool over stdio and classify the result.
|
|
4
|
+
*
|
|
5
|
+
* Distinguishes three outcomes:
|
|
6
|
+
* ✅ returned data — worked
|
|
7
|
+
* 🟡 clean error — failed, but reported it properly
|
|
8
|
+
* 💥 crash-like — leaked a TypeError / undefined access to the client
|
|
9
|
+
*
|
|
10
|
+
* The point is the third category. A tool that throws a raw TypeError at an MCP
|
|
11
|
+
* client during a live draft is unusable; one that says "Yahoo returned 403" is
|
|
12
|
+
* merely blocked. Run this whenever Yahoo is unreachable — an outage is the
|
|
13
|
+
* cheapest way to exercise every failure path at once.
|
|
14
|
+
*
|
|
15
|
+
* npm run smoke
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { spawn } from 'child_process';
|
|
19
|
+
|
|
20
|
+
const TOOLS = [
|
|
21
|
+
['set_roster', { roster_text: 'C\tAuston Matthews\tTOR - C\nD\tCale Makar\tCOL - D\nG\tIgor Shesterkin\tNYR - G\nLW\tKirill Kaprizov\tMIN - LW', team_name: 'Smoke Team' }],
|
|
22
|
+
['set_opponent_roster', { roster_text: 'Connor McDavid\nNathan MacKinnon\nQuinn Hughes', team_name: 'Smoke Opponent' }],
|
|
23
|
+
['set_standings', { standings_text: '1. Smoke Team 8-2-1 142 pts\n2. Smoke Opponent 7-3-1 138 pts' }],
|
|
24
|
+
['show_stored_data', {}],
|
|
25
|
+
['get_team_roster', {}],
|
|
26
|
+
['get_league_standings', {}],
|
|
27
|
+
['search_players', { position: 'C', count: 5 }],
|
|
28
|
+
['get_player_stats', { player_id: 'Cale Makar' }],
|
|
29
|
+
['compare_matchup', {}],
|
|
30
|
+
['optimize_lineup', {}],
|
|
31
|
+
['get_streaming_recommendations', {}],
|
|
32
|
+
['get_games_in_hand', {}],
|
|
33
|
+
['get_roster_transaction_recommendations', {}],
|
|
34
|
+
['ice', {}],
|
|
35
|
+
['governance_dashboard', {}],
|
|
36
|
+
['analyze_breakout_players', { max_results: 5 }],
|
|
37
|
+
['analyze_weekend_streams', { date_range: { start: '2026-10-09', end: '2026-10-11' } }],
|
|
38
|
+
['chirp_opponent', {}],
|
|
39
|
+
['analyze_trade', { giving: ['Cale Makar'], receiving: ['Quinn Hughes'] }],
|
|
40
|
+
['schedule_value', { teams: ['TOR', 'SEA'], playoff_start_week: 22, playoff_end_week: 24 }],
|
|
41
|
+
['chirp_draft_pick', { pick_number: 5, max_results: 5 }],
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
const proc = spawn(process.execPath, ['build/index.js'], { stdio: ['pipe', 'pipe', 'pipe'] });
|
|
45
|
+
|
|
46
|
+
let buf = '';
|
|
47
|
+
const results = new Map();
|
|
48
|
+
proc.stdout.on('data', d => {
|
|
49
|
+
buf += d;
|
|
50
|
+
let i;
|
|
51
|
+
while ((i = buf.indexOf('\n')) >= 0) {
|
|
52
|
+
const line = buf.slice(0, i); buf = buf.slice(i + 1);
|
|
53
|
+
if (!line.trim()) continue;
|
|
54
|
+
try {
|
|
55
|
+
const m = JSON.parse(line);
|
|
56
|
+
if (typeof m.id === 'number' && m.id >= 100) results.set(m.id, m);
|
|
57
|
+
} catch {}
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const send = o => proc.stdin.write(JSON.stringify(o) + '\n');
|
|
62
|
+
send({ jsonrpc:'2.0', id:1, method:'initialize', params:{ protocolVersion:'2024-11-05', capabilities:{}, clientInfo:{name:'t',version:'1'} } });
|
|
63
|
+
send({ jsonrpc:'2.0', method:'notifications/initialized' });
|
|
64
|
+
await new Promise(r => setTimeout(r, 1500));
|
|
65
|
+
|
|
66
|
+
for (let i = 0; i < TOOLS.length; i++) {
|
|
67
|
+
const [name, args] = TOOLS[i];
|
|
68
|
+
send({ jsonrpc:'2.0', id:100+i, method:'tools/call', params:{ name, arguments: args } });
|
|
69
|
+
// The first four establish the league state everything else reads.
|
|
70
|
+
if (i < 4) { const t0=Date.now(); while (!results.has(100+i) && Date.now()-t0 < 30000) await new Promise(r=>setTimeout(r,150)); }
|
|
71
|
+
}
|
|
72
|
+
await new Promise(r => setTimeout(r, 40000));
|
|
73
|
+
|
|
74
|
+
console.log('\nTool behaviour (v4 — no account, NHL public data only):\n');
|
|
75
|
+
let crashed = 0, degraded = 0, worked = 0, missing = 0;
|
|
76
|
+
TOOLS.forEach(([name], i) => {
|
|
77
|
+
const m = results.get(100 + i);
|
|
78
|
+
if (!m) { console.log(` ⏳ ${name.padEnd(40)} NO RESPONSE`); missing++; return; }
|
|
79
|
+
const text = m.result?.content?.[0]?.text ?? JSON.stringify(m.error ?? {});
|
|
80
|
+
const isErr = m.result?.isError === true || Boolean(m.error);
|
|
81
|
+
const has403 = /403|not authorized/i.test(text);
|
|
82
|
+
const crashLike = /TypeError|undefined is not|Cannot read|is not a function/i.test(text);
|
|
83
|
+
if (crashLike) { console.log(` 💥 ${name.padEnd(40)} CRASH-LIKE: ${text.slice(0,90).replace(/\n/g,' ')}`); crashed++; }
|
|
84
|
+
else if (has403 || isErr) { console.log(` 🟡 ${name.padEnd(40)} clean error`); degraded++; }
|
|
85
|
+
else { console.log(` ✅ ${name.padEnd(40)} returned data`); worked++; }
|
|
86
|
+
});
|
|
87
|
+
console.log(`\n ✅ ${worked} worked 🟡 ${degraded} degraded cleanly 💥 ${crashed} crash-like ⏳ ${missing} no response`);
|
|
88
|
+
proc.kill();
|
|
89
|
+
|
|
90
|
+
// Only a crash-like response or a missing one is a failure. A clean error is
|
|
91
|
+
// the correct behaviour when the upstream API is unavailable.
|
|
92
|
+
process.exit(crashed > 0 || missing > 0 ? 1 : 0);
|
package/.env.example
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
# Get these from https://developer.yahoo.com/apps/create/
|
|
2
|
-
YAHOO_CLIENT_ID=your_client_id_here
|
|
3
|
-
YAHOO_CLIENT_SECRET=your_client_secret_here
|
|
4
|
-
|
|
5
|
-
# Your league and team IDs, from your team URL:
|
|
6
|
-
# https://hockey.fantasysports.yahoo.com/hockey/{LEAGUE_ID}/{TEAM_ID}
|
|
7
|
-
YAHOO_LEAGUE_ID=your_league_id_here
|
|
8
|
-
YAHOO_TEAM_ID=your_team_id_here
|
package/authenticate.js
DELETED
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
// OAuth Helper Script for Yahoo Fantasy
|
|
2
|
-
// Run this ONCE to get your access token
|
|
3
|
-
// Usage: node authenticate.js
|
|
4
|
-
|
|
5
|
-
import * as fs from 'fs';
|
|
6
|
-
import * as dotenv from 'dotenv';
|
|
7
|
-
import * as https from 'https';
|
|
8
|
-
import * as url from 'url';
|
|
9
|
-
import selfsigned from 'selfsigned';
|
|
10
|
-
|
|
11
|
-
dotenv.config();
|
|
12
|
-
|
|
13
|
-
const CLIENT_ID = process.env.YAHOO_CLIENT_ID;
|
|
14
|
-
const CLIENT_SECRET = process.env.YAHOO_CLIENT_SECRET;
|
|
15
|
-
const REDIRECT_URI = 'https://localhost:3000/callback';
|
|
16
|
-
const TOKEN_FILE = '.yahoo-oauth.json';
|
|
17
|
-
|
|
18
|
-
if (!CLIENT_ID || !CLIENT_SECRET) {
|
|
19
|
-
console.error('❌ Missing YAHOO_CLIENT_ID or YAHOO_CLIENT_SECRET in .env');
|
|
20
|
-
console.error('📝 Please create a .env file with your Yahoo API credentials');
|
|
21
|
-
console.error(' Get them from: https://developer.yahoo.com/apps/create/');
|
|
22
|
-
process.exit(1);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Generate self-signed certificate for local HTTPS
|
|
26
|
-
console.log('🔐 Generating self-signed certificate for HTTPS...');
|
|
27
|
-
const attrs = [{ name: 'commonName', value: 'localhost' }];
|
|
28
|
-
const pems = selfsigned.generate(attrs, {
|
|
29
|
-
keySize: 2048,
|
|
30
|
-
days: 365,
|
|
31
|
-
algorithm: 'sha256',
|
|
32
|
-
extensions: [
|
|
33
|
-
{
|
|
34
|
-
name: 'subjectAltName',
|
|
35
|
-
altNames: [
|
|
36
|
-
{ type: 2, value: 'localhost' },
|
|
37
|
-
{ type: 7, ip: '127.0.0.1' }
|
|
38
|
-
]
|
|
39
|
-
}
|
|
40
|
-
]
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
console.log('🔐 Starting Yahoo OAuth flow...\n');
|
|
44
|
-
|
|
45
|
-
// HTTPS server options with self-signed certificate
|
|
46
|
-
const serverOptions = {
|
|
47
|
-
key: pems.private,
|
|
48
|
-
cert: pems.cert,
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
// Create an HTTPS server to handle the callback
|
|
52
|
-
const server = https.createServer(serverOptions, async (req, res) => {
|
|
53
|
-
const parsedUrl = url.parse(req.url, true);
|
|
54
|
-
|
|
55
|
-
if (parsedUrl.pathname === '/') {
|
|
56
|
-
// Build Yahoo OAuth authorization URL
|
|
57
|
-
const authUrl = `https://api.login.yahoo.com/oauth2/request_auth?client_id=${CLIENT_ID}&redirect_uri=${encodeURIComponent(REDIRECT_URI)}&response_type=code&language=en-us`;
|
|
58
|
-
|
|
59
|
-
res.writeHead(302, { 'Location': authUrl });
|
|
60
|
-
res.end();
|
|
61
|
-
console.log('🔐 Redirecting to Yahoo for authorization...');
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (parsedUrl.pathname === '/callback') {
|
|
66
|
-
const authCode = parsedUrl.query.code;
|
|
67
|
-
|
|
68
|
-
if (!authCode) {
|
|
69
|
-
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
70
|
-
res.end('<h1>❌ Error: No authorization code received</h1>');
|
|
71
|
-
setTimeout(() => {
|
|
72
|
-
server.close();
|
|
73
|
-
process.exit(1);
|
|
74
|
-
}, 1000);
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
try {
|
|
79
|
-
console.log('📝 Exchanging authorization code for access token...');
|
|
80
|
-
|
|
81
|
-
// Exchange the code for a token
|
|
82
|
-
const tokenResponse = await fetch('https://api.login.yahoo.com/oauth2/get_token', {
|
|
83
|
-
method: 'POST',
|
|
84
|
-
headers: {
|
|
85
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
86
|
-
'Authorization': 'Basic ' + Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString('base64')
|
|
87
|
-
},
|
|
88
|
-
body: new URLSearchParams({
|
|
89
|
-
grant_type: 'authorization_code',
|
|
90
|
-
redirect_uri: REDIRECT_URI,
|
|
91
|
-
code: authCode
|
|
92
|
-
})
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
if (!tokenResponse.ok) {
|
|
96
|
-
throw new Error(`Token exchange failed: ${tokenResponse.status} ${tokenResponse.statusText}`);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const token = await tokenResponse.json();
|
|
100
|
-
console.log('📝 Token retrieved successfully');
|
|
101
|
-
|
|
102
|
-
// Save the token with timestamp
|
|
103
|
-
const tokenWithTimestamp = {
|
|
104
|
-
access_token: token.access_token,
|
|
105
|
-
refresh_token: token.refresh_token,
|
|
106
|
-
expires_in: token.expires_in,
|
|
107
|
-
token_type: token.token_type,
|
|
108
|
-
xoauth_yahoo_guid: token.xoauth_yahoo_guid,
|
|
109
|
-
timestamp: Date.now(),
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
fs.writeFileSync(TOKEN_FILE, JSON.stringify(tokenWithTimestamp, null, 2));
|
|
113
|
-
console.log(`✅ Token saved to ${TOKEN_FILE}`);
|
|
114
|
-
|
|
115
|
-
// Success page
|
|
116
|
-
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
117
|
-
res.end(`
|
|
118
|
-
<html>
|
|
119
|
-
<head>
|
|
120
|
-
<title>🏒 Authentication Successful - ICE Activated</title>
|
|
121
|
-
<style>
|
|
122
|
-
body {
|
|
123
|
-
font-family: Arial, sans-serif;
|
|
124
|
-
padding: 50px;
|
|
125
|
-
text-align: center;
|
|
126
|
-
background: linear-gradient(135deg, #0891b2 0%, #06b6d4 100%);
|
|
127
|
-
color: white;
|
|
128
|
-
}
|
|
129
|
-
.container {
|
|
130
|
-
background: white;
|
|
131
|
-
color: #333;
|
|
132
|
-
padding: 40px;
|
|
133
|
-
border-radius: 10px;
|
|
134
|
-
max-width: 500px;
|
|
135
|
-
margin: 0 auto;
|
|
136
|
-
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
|
|
137
|
-
}
|
|
138
|
-
h1 { color: #0891b2; }
|
|
139
|
-
.emoji { font-size: 48px; margin: 20px 0; }
|
|
140
|
-
code {
|
|
141
|
-
background: #f5f5f5;
|
|
142
|
-
padding: 2px 6px;
|
|
143
|
-
border-radius: 3px;
|
|
144
|
-
color: #0891b2;
|
|
145
|
-
}
|
|
146
|
-
</style>
|
|
147
|
-
</head>
|
|
148
|
-
<body>
|
|
149
|
-
<div class="container">
|
|
150
|
-
<div class="emoji">🏒✅❄️</div>
|
|
151
|
-
<h1>ICE Activated!</h1>
|
|
152
|
-
<p>Yahoo authentication successful. Intent Chirp Engine is ready to dominate.</p>
|
|
153
|
-
<p>You can close this window and return to your terminal.</p>
|
|
154
|
-
<hr>
|
|
155
|
-
<p><strong>Next steps:</strong></p>
|
|
156
|
-
<ol style="text-align: left; display: inline-block;">
|
|
157
|
-
<li>Server is built and ready</li>
|
|
158
|
-
<li>Test with: <code>npm start</code></li>
|
|
159
|
-
<li>Add to Claude Desktop config</li>
|
|
160
|
-
<li>Start getting chirped with winning insights</li>
|
|
161
|
-
</ol>
|
|
162
|
-
</div>
|
|
163
|
-
</body>
|
|
164
|
-
</html>
|
|
165
|
-
`);
|
|
166
|
-
|
|
167
|
-
// Close server after success
|
|
168
|
-
setTimeout(() => {
|
|
169
|
-
server.close();
|
|
170
|
-
console.log('\n🏒 ICE is ready! Next steps:');
|
|
171
|
-
console.log(' 1. Test the server: npm start');
|
|
172
|
-
console.log(' 2. Add to Claude Desktop config (see ACTIVATION_STEPS.md)');
|
|
173
|
-
console.log(' 3. Start dominating your fantasy league with semantic chirps');
|
|
174
|
-
process.exit(0);
|
|
175
|
-
}, 1000);
|
|
176
|
-
} catch (error) {
|
|
177
|
-
console.error('❌ Error during callback:', error);
|
|
178
|
-
res.writeHead(500, { 'Content-Type': 'text/html' });
|
|
179
|
-
res.end(`
|
|
180
|
-
<html>
|
|
181
|
-
<head><title>Authentication Failed</title></head>
|
|
182
|
-
<body style="font-family: Arial; padding: 50px; text-align: center;">
|
|
183
|
-
<h1 style="color: #f44336;">❌ Authentication Failed</h1>
|
|
184
|
-
<p>Check the terminal for error details.</p>
|
|
185
|
-
</body>
|
|
186
|
-
</html>
|
|
187
|
-
`);
|
|
188
|
-
setTimeout(() => {
|
|
189
|
-
server.close();
|
|
190
|
-
process.exit(1);
|
|
191
|
-
}, 1000);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
server.listen(3000, () => {
|
|
197
|
-
console.log('🌐 HTTPS Server started on https://localhost:3000');
|
|
198
|
-
console.log('\n👉 Open this URL in your browser to start authentication:');
|
|
199
|
-
console.log(' https://localhost:3000/\n');
|
|
200
|
-
console.log('⏳ Waiting for authentication...\n');
|
|
201
|
-
|
|
202
|
-
// Helpful reminders
|
|
203
|
-
console.log('💡 Make sure your Yahoo app has this redirect URI configured:');
|
|
204
|
-
console.log(' https://localhost:3000/callback\n');
|
|
205
|
-
console.log('⚠️ Your browser will show a security warning (self-signed cert)');
|
|
206
|
-
console.log(' Click "Advanced" → "Proceed to localhost" to continue\n');
|
|
207
|
-
});
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Semantic Breakout Tool Integration
|
|
3
|
-
*
|
|
4
|
-
* Implements breakout player analysis using semantic intent pattern.
|
|
5
|
-
* This tool uses natural language intent to auto-configure the MCP tool.
|
|
6
|
-
*/
|
|
7
|
-
import { SemanticIntentParser } from './semantic-intent-parser.js';
|
|
8
|
-
/**
|
|
9
|
-
* Semantic tool definition for breakout player analysis
|
|
10
|
-
*
|
|
11
|
-
* This comprehensive prompt integrates:
|
|
12
|
-
* - Data-driven predictability (40% recent, 30% projections, 20% opportunity, 10% risk)
|
|
13
|
-
* - External source references (Rotowire, NHL EDGE, DobberHockey)
|
|
14
|
-
* - Position-specific filtering
|
|
15
|
-
* - League context awareness
|
|
16
|
-
*/
|
|
17
|
-
export const SEMANTIC_BREAKOUT_ANALYSIS = {
|
|
18
|
-
name: "analyze_breakout_players",
|
|
19
|
-
description: "Analyze free agents to identify top pickups and breakout candidates using comprehensive data-driven scoring",
|
|
20
|
-
semanticIntent: `
|
|
21
|
-
I analyze free agents in Yahoo Fantasy Hockey to recommend top 5-10 pickups and 3-5 breakout candidates.
|
|
22
|
-
I use a predictable scoring formula: 40% recent performance + 30% projections + 20% opportunity - 10% risk.
|
|
23
|
-
I focus on players under 50% owned and provide position-specific analysis.
|
|
24
|
-
|
|
25
|
-
I need: position filter (optional array of strings like ["C", "RW"]),
|
|
26
|
-
ownership threshold (optional number, default 50),
|
|
27
|
-
breakout age max (optional number, default 26),
|
|
28
|
-
minimum score (optional number, default 0),
|
|
29
|
-
max results (optional number, default 10),
|
|
30
|
-
chirp intensity (optional string),
|
|
31
|
-
personality mode (optional string),
|
|
32
|
-
enable chirp (optional boolean)
|
|
33
|
-
|
|
34
|
-
I will: Yahoo API calls, statistical analysis, trend detection, opportunity scoring, risk assessment
|
|
35
|
-
|
|
36
|
-
I return: Top pickups with scores, breakout candidates, position breakdown, market intelligence
|
|
37
|
-
|
|
38
|
-
I estimate: moderate complexity, 3000 tokens
|
|
39
|
-
`
|
|
40
|
-
};
|
|
41
|
-
/**
|
|
42
|
-
* Parse semantic intent for breakout analysis
|
|
43
|
-
*/
|
|
44
|
-
export function parseBreakoutAnalysisIntent() {
|
|
45
|
-
const parser = new SemanticIntentParser();
|
|
46
|
-
return parser.parseIntent(SEMANTIC_BREAKOUT_ANALYSIS.semanticIntent);
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Get MCP input schema from semantic intent
|
|
50
|
-
*/
|
|
51
|
-
export function getBreakoutAnalysisInputSchema() {
|
|
52
|
-
const parsed = parseBreakoutAnalysisIntent();
|
|
53
|
-
// Build schema from parsed parameters
|
|
54
|
-
const properties = {};
|
|
55
|
-
const required = [];
|
|
56
|
-
for (const param of parsed.parameters) {
|
|
57
|
-
properties[param.name] = {
|
|
58
|
-
type: param.type,
|
|
59
|
-
description: param.description
|
|
60
|
-
};
|
|
61
|
-
if (param.required) {
|
|
62
|
-
required.push(param.name);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
// Add enum constraints for specific parameters
|
|
66
|
-
if (properties.chirp_intensity) {
|
|
67
|
-
properties.chirp_intensity.enum = ['gentle', 'standard', 'savage', 'ice_cold'];
|
|
68
|
-
}
|
|
69
|
-
if (properties.personality_mode) {
|
|
70
|
-
properties.personality_mode.enum = ['analytical', 'motivational', 'roast_master', 'championship_coach'];
|
|
71
|
-
}
|
|
72
|
-
if (properties.position_filter) {
|
|
73
|
-
properties.position_filter.items = { type: 'string' };
|
|
74
|
-
}
|
|
75
|
-
return {
|
|
76
|
-
type: "object",
|
|
77
|
-
properties,
|
|
78
|
-
required: required.length > 0 ? required : undefined
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Execute breakout analysis with semantic configuration
|
|
83
|
-
*/
|
|
84
|
-
export async function executeBreakoutAnalysis(args, breakoutAnalysis) {
|
|
85
|
-
const parsed = parseBreakoutAnalysisIntent();
|
|
86
|
-
// Build semantic contract
|
|
87
|
-
const semanticContract = {
|
|
88
|
-
chirp_intensity: args.chirp_intensity || 'standard',
|
|
89
|
-
personality_mode: args.personality_mode || 'analytical',
|
|
90
|
-
enable_chirp: args.enable_chirp !== false,
|
|
91
|
-
semantic_intent: 'user_requested',
|
|
92
|
-
tool_context: 'analyze_breakout_players'
|
|
93
|
-
};
|
|
94
|
-
// Build analysis args
|
|
95
|
-
const analysisArgs = {
|
|
96
|
-
position_filter: args.position_filter,
|
|
97
|
-
ownership_threshold: args.ownership_threshold,
|
|
98
|
-
breakout_age_max: args.breakout_age_max,
|
|
99
|
-
min_score: args.min_score,
|
|
100
|
-
max_results: args.max_results
|
|
101
|
-
};
|
|
102
|
-
try {
|
|
103
|
-
// Execute analysis using template pattern
|
|
104
|
-
const result = await breakoutAnalysis.executeAnalysis(analysisArgs, semanticContract);
|
|
105
|
-
// Enhance with semantic metadata
|
|
106
|
-
return {
|
|
107
|
-
...result,
|
|
108
|
-
_semantic_metadata: {
|
|
109
|
-
tool_name: SEMANTIC_BREAKOUT_ANALYSIS.name,
|
|
110
|
-
parsed_capabilities: parsed.capabilities,
|
|
111
|
-
parse_confidence: `${(parsed.confidence * 100).toFixed(0)}%`,
|
|
112
|
-
message: '✅ Tool auto-configured from semantic intent!',
|
|
113
|
-
prompt_integration: {
|
|
114
|
-
scoring_formula: '40% recent + 30% projections + 20% opportunity - 10% risk',
|
|
115
|
-
external_sources: 'Ready for: Rotowire, NHL EDGE, DobberHockey integration',
|
|
116
|
-
data_driven: 'Predictable rankings with confidence scores'
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
catch (error) {
|
|
122
|
-
throw new Error(`Breakout analysis failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Improved prompt recommendations for Claude Desktop integration
|
|
127
|
-
*/
|
|
128
|
-
export const BREAKOUT_PROMPT_IMPROVEMENTS = {
|
|
129
|
-
semantic_clarity: {
|
|
130
|
-
original: "Complex multi-paragraph template with embedded formulas",
|
|
131
|
-
improved: "Structured semantic intent with clear I need/I will/I return sections",
|
|
132
|
-
benefit: "Claude Desktop can better understand tool purpose and auto-suggest when user asks about breakouts"
|
|
133
|
-
},
|
|
134
|
-
parameter_discovery: {
|
|
135
|
-
original: "Parameters embedded in prose",
|
|
136
|
-
improved: "Explicit parameter definitions with types and optionality",
|
|
137
|
-
benefit: "MCP can auto-generate input schema, reducing manual configuration"
|
|
138
|
-
},
|
|
139
|
-
capability_mapping: {
|
|
140
|
-
original: "References to external sources without integration plan",
|
|
141
|
-
improved: "Capability tags (yahoo_api, data_analysis) that map to available functions",
|
|
142
|
-
benefit: "Tool knows what it can and cannot do, preventing hallucination"
|
|
143
|
-
},
|
|
144
|
-
predictability_enhancement: {
|
|
145
|
-
original: "Scoring formula mentioned in prose",
|
|
146
|
-
improved: "Formula implemented in code with observable weights",
|
|
147
|
-
benefit: "Consistent, repeatable results that users can trust"
|
|
148
|
-
},
|
|
149
|
-
integration_points: {
|
|
150
|
-
yahoo_api: "Direct integration via YahooApiClient",
|
|
151
|
-
rotowire: "Placeholder for future web scraping capability",
|
|
152
|
-
nhl_edge: "Placeholder for NHL API integration",
|
|
153
|
-
dobber_hockey: "Placeholder for prospect data integration"
|
|
154
|
-
},
|
|
155
|
-
usage_with_claude_desktop: `
|
|
156
|
-
When user asks: "tell me about breakout players" or "who should I pick up?"
|
|
157
|
-
|
|
158
|
-
Claude Desktop will:
|
|
159
|
-
1. Recognize semantic intent matches analyze_breakout_players tool
|
|
160
|
-
2. Auto-extract parameters from conversation context (league format, roster needs)
|
|
161
|
-
3. Call tool with appropriate chirp settings (analytical by default)
|
|
162
|
-
4. Present results in conversational format with player tables and reasoning
|
|
163
|
-
|
|
164
|
-
Example interaction:
|
|
165
|
-
User: "I need a right wing, who are the best breakout candidates?"
|
|
166
|
-
|
|
167
|
-
Claude: *uses analyze_breakout_players with position_filter=["RW"]*
|
|
168
|
-
|
|
169
|
-
"Based on data-driven analysis, here are the top RW breakout candidates:
|
|
170
|
-
|
|
171
|
-
🏒 Must-Adds (Score 80+):
|
|
172
|
-
1. [Player Name] (Team) - 85 score
|
|
173
|
-
- Catalyst: Top-6 center opportunity
|
|
174
|
-
- Recent: 0.9 PPG | Projected: 0.7 FPG
|
|
175
|
-
- Risk: Low (15%)
|
|
176
|
-
- Confidence: High
|
|
177
|
-
|
|
178
|
-
2. [Player Name] (Team) - 82 score
|
|
179
|
-
...
|
|
180
|
-
|
|
181
|
-
📊 Position Analysis:
|
|
182
|
-
- RW pool strength: 15 candidates with 65+ scores
|
|
183
|
-
- Market trend: RW pickups trending up 23%
|
|
184
|
-
- Recommendation: Act fast on must-adds
|
|
185
|
-
|
|
186
|
-
💡 Next steps: Should I analyze your roster to see who you could drop?"
|
|
187
|
-
`
|
|
188
|
-
};
|