starthub-mcp 0.1.0 → 0.1.1
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/build/index.js +1 -1
- package/build/tools/candidate.js +22 -34
- package/package.json +1 -1
package/build/index.js
CHANGED
|
@@ -25,7 +25,7 @@ async function main() {
|
|
|
25
25
|
});
|
|
26
26
|
const supabase = getSupabase();
|
|
27
27
|
if (isCandidate) {
|
|
28
|
-
registerCandidateTools(server, supabase, auth.id);
|
|
28
|
+
registerCandidateTools(server, supabase, auth.id, STARTHUB_KEY);
|
|
29
29
|
}
|
|
30
30
|
else {
|
|
31
31
|
registerStartupTools(server, supabase, auth);
|
package/build/tools/candidate.js
CHANGED
|
@@ -8,17 +8,13 @@ const APP_STAGES = [
|
|
|
8
8
|
'applied', 'screening', 'interview-1', 'interview-2',
|
|
9
9
|
'offer', 'hired', 'rejected',
|
|
10
10
|
];
|
|
11
|
-
export function registerCandidateTools(server, supabase, candidateId) {
|
|
11
|
+
export function registerCandidateTools(server, supabase, candidateId, mcpKey) {
|
|
12
12
|
// ── get_profile ────────────────────────────────────────────
|
|
13
13
|
server.registerTool('get_profile', {
|
|
14
14
|
description: 'Leggi i tuoi dati profilo: bio, ruoli cercati, RAL, preferenze, visibilità.',
|
|
15
15
|
inputSchema: {},
|
|
16
16
|
}, async () => {
|
|
17
|
-
const { data, error } = await supabase
|
|
18
|
-
.from('candidates')
|
|
19
|
-
.select('id, full_name, email, bio, role_targets, ral_min, ral_max, work_mode_pref, cities_pref, linkedin_url, is_searchable, created_at')
|
|
20
|
-
.eq('id', candidateId)
|
|
21
|
-
.single();
|
|
17
|
+
const { data, error } = await supabase.rpc('get_candidate_by_key', { p_key: mcpKey });
|
|
22
18
|
if (error || !data)
|
|
23
19
|
throw new Error('Profilo non trovato.');
|
|
24
20
|
return {
|
|
@@ -52,7 +48,10 @@ export function registerCandidateTools(server, supabase, candidateId) {
|
|
|
52
48
|
if (Object.keys(updates).length === 0) {
|
|
53
49
|
return { content: [{ type: 'text', text: 'Nessun campo da aggiornare.' }] };
|
|
54
50
|
}
|
|
55
|
-
const { error } = await supabase.
|
|
51
|
+
const { error } = await supabase.rpc('update_candidate_by_key', {
|
|
52
|
+
p_key: mcpKey,
|
|
53
|
+
p_updates: updates,
|
|
54
|
+
});
|
|
56
55
|
if (error)
|
|
57
56
|
throw new Error(error.message);
|
|
58
57
|
return { content: [{ type: 'text', text: `✅ Profilo aggiornato: ${Object.keys(updates).join(', ')}.` }] };
|
|
@@ -64,10 +63,10 @@ export function registerCandidateTools(server, supabase, candidateId) {
|
|
|
64
63
|
visible: z.boolean().describe('true = visibile alle startup | false = nascosto'),
|
|
65
64
|
},
|
|
66
65
|
}, async ({ visible }) => {
|
|
67
|
-
const { error } = await supabase
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
66
|
+
const { error } = await supabase.rpc('update_candidate_by_key', {
|
|
67
|
+
p_key: mcpKey,
|
|
68
|
+
p_updates: { is_searchable: visible },
|
|
69
|
+
});
|
|
71
70
|
if (error)
|
|
72
71
|
throw new Error(error.message);
|
|
73
72
|
const text = visible
|
|
@@ -165,23 +164,16 @@ export function registerCandidateTools(server, supabase, candidateId) {
|
|
|
165
164
|
.single();
|
|
166
165
|
if (!job)
|
|
167
166
|
throw new Error('Offerta non trovata o non più attiva.');
|
|
168
|
-
const { data:
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
.eq('job_posting_id', job_id)
|
|
173
|
-
.single();
|
|
174
|
-
if (existing) {
|
|
175
|
-
return { content: [{ type: 'text', text: `Hai già applicato. Stage attuale: ${existing.stage}.` }] };
|
|
176
|
-
}
|
|
177
|
-
const { error } = await supabase.from('applications').insert({
|
|
178
|
-
candidate_id: candidateId,
|
|
179
|
-
job_posting_id: job_id,
|
|
180
|
-
cover_note: cover_note ?? null,
|
|
181
|
-
stage: 'applied',
|
|
167
|
+
const { data: result, error } = await supabase.rpc('insert_application_by_key', {
|
|
168
|
+
p_key: mcpKey,
|
|
169
|
+
p_job_posting_id: job_id,
|
|
170
|
+
p_cover_note: cover_note ?? null,
|
|
182
171
|
});
|
|
183
172
|
if (error)
|
|
184
173
|
throw new Error(error.message);
|
|
174
|
+
if (result?.already_applied) {
|
|
175
|
+
return { content: [{ type: 'text', text: `Hai già applicato. Stage attuale: ${result.stage}.` }] };
|
|
176
|
+
}
|
|
185
177
|
const startupName = job.startups?.name ?? 'la startup';
|
|
186
178
|
return { content: [{ type: 'text', text: `✅ Candidatura inviata per ${job.role_title} @ ${startupName}. In bocca al lupo!` }] };
|
|
187
179
|
});
|
|
@@ -192,17 +184,13 @@ export function registerCandidateTools(server, supabase, candidateId) {
|
|
|
192
184
|
stage: z.enum(APP_STAGES).optional().describe('Filtra per stage (opzionale)'),
|
|
193
185
|
},
|
|
194
186
|
}, async ({ stage }) => {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
.order('applied_at', { ascending: false });
|
|
200
|
-
if (stage)
|
|
201
|
-
query = query.eq('stage', stage);
|
|
202
|
-
const { data, error } = await query;
|
|
187
|
+
const { data, error } = await supabase.rpc('get_applications_by_key', {
|
|
188
|
+
p_key: mcpKey,
|
|
189
|
+
p_stage: stage ?? null,
|
|
190
|
+
});
|
|
203
191
|
if (error)
|
|
204
192
|
throw new Error(error.message);
|
|
205
|
-
if (!data
|
|
193
|
+
if (!data || (Array.isArray(data) && data.length === 0)) {
|
|
206
194
|
return { content: [{ type: 'text', text: 'Nessuna candidatura. Usa search_jobs e apply per candidarti.' }] };
|
|
207
195
|
}
|
|
208
196
|
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|