@ai-uni/mcp-server 0.1.3 → 0.1.5
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/dist/index.js +618 -3
- package/package.json +1 -1
- package/prompts/session-panel.html +16 -10
- package/prompts/tutor-system.md +3 -2
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ const TUTOR_INSTRUCTIONS = `You are the AI Uni tutor — a Socratic learning par
|
|
|
8
8
|
|
|
9
9
|
## First Action (Every Conversation)
|
|
10
10
|
|
|
11
|
-
**Before saying anything**, call \`get_student_context\`.
|
|
11
|
+
**Before saying anything**, call \`get_student_context\` and \`get_session_panel\`. The first tells you who the student is and where they are in the curriculum. The second returns an HTML session panel — render it as an artifact (title: "AI Uni — Session Panel", type: HTML) exactly as returned, with no modifications.
|
|
12
12
|
|
|
13
13
|
After reviewing context, greet the student by name and summarize where they are:
|
|
14
14
|
- If they have a session in progress, offer to pick up where they left off.
|
|
@@ -47,11 +47,12 @@ A typical tutoring session follows this arc:
|
|
|
47
47
|
|
|
48
48
|
## Using Your Tools
|
|
49
49
|
|
|
50
|
-
You have
|
|
50
|
+
You have seven MCP tools. Use them proactively — don't wait for the student to ask.
|
|
51
51
|
|
|
52
52
|
| Tool | When to Use |
|
|
53
53
|
|------|-------------|
|
|
54
54
|
| \`get_student_context\` | Start of every conversation. No exceptions. |
|
|
55
|
+
| \`get_session_panel\` | Start of every conversation, alongside \`get_student_context\`. Render the returned HTML as an artifact. |
|
|
55
56
|
| \`get_current_assignment\` | After context check, to load the session brief. |
|
|
56
57
|
| \`get_rubric\` | Before evaluating student work. Never evaluate without it. |
|
|
57
58
|
| \`submit_session_complete\` | Only when all acceptance criteria are met. Never premature. |
|
|
@@ -93,7 +94,586 @@ You have six MCP tools. Use them proactively — don't wait for the student to a
|
|
|
93
94
|
**Student hasn't been here in a while:** Check \`get_student_context\` for session notes from last time. Summarize what was covered and ask what they remember. Quick recap, then continue.
|
|
94
95
|
|
|
95
96
|
**Student asks about AI Uni itself (pricing, other courses, etc.):** You're the tutor, not the sales team. Direct them to aiuni.tech for program information. Stay focused on their learning.`;
|
|
96
|
-
const
|
|
97
|
+
const SESSION_PANEL_HTML = `<!DOCTYPE html>
|
|
98
|
+
<html lang="en">
|
|
99
|
+
<head>
|
|
100
|
+
<meta charset="UTF-8">
|
|
101
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
102
|
+
<title>AI Uni — Session Panel</title>
|
|
103
|
+
<style>
|
|
104
|
+
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&family=IBM+Plex+Sans:ital,wght@0,300;0,400;0,500;1,300&display=swap');
|
|
105
|
+
|
|
106
|
+
:root {
|
|
107
|
+
--bg: #0d0f0e;
|
|
108
|
+
--surface: #131614;
|
|
109
|
+
--surface2: #181c19;
|
|
110
|
+
--border: #232825;
|
|
111
|
+
--border-hi: #2d3530;
|
|
112
|
+
--green: #4ade80;
|
|
113
|
+
--green-dim: #163324;
|
|
114
|
+
--green-glow: rgba(74,222,128,0.08);
|
|
115
|
+
--text: #dde8e1;
|
|
116
|
+
--dim: #6b7d72;
|
|
117
|
+
--muted: #323d36;
|
|
118
|
+
--blue: #7ab8f5;
|
|
119
|
+
--blue-dim: #172233;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
123
|
+
|
|
124
|
+
body {
|
|
125
|
+
background: var(--bg);
|
|
126
|
+
color: var(--text);
|
|
127
|
+
font-family: 'IBM Plex Sans', sans-serif;
|
|
128
|
+
font-size: 13px;
|
|
129
|
+
min-height: 100vh;
|
|
130
|
+
padding: 18px 16px 24px;
|
|
131
|
+
width: 320px;
|
|
132
|
+
max-width: 320px;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.hd {
|
|
136
|
+
display: flex;
|
|
137
|
+
align-items: center;
|
|
138
|
+
justify-content: space-between;
|
|
139
|
+
margin-bottom: 14px;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.brand {
|
|
143
|
+
font-family: 'IBM Plex Sans', sans-serif;
|
|
144
|
+
font-size: 14px;
|
|
145
|
+
font-weight: 600;
|
|
146
|
+
color: var(--text);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.session-badge {
|
|
150
|
+
font-family: 'IBM Plex Mono', monospace;
|
|
151
|
+
font-size: 10px;
|
|
152
|
+
color: var(--dim);
|
|
153
|
+
background: var(--surface2);
|
|
154
|
+
border: 1px solid var(--border);
|
|
155
|
+
border-radius: 4px;
|
|
156
|
+
padding: 3px 8px;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.hint {
|
|
160
|
+
font-size: 11px;
|
|
161
|
+
color: var(--dim);
|
|
162
|
+
margin-bottom: 10px;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.status {
|
|
166
|
+
background: var(--surface);
|
|
167
|
+
border: 1px solid var(--border);
|
|
168
|
+
border-radius: 7px;
|
|
169
|
+
padding: 11px 13px;
|
|
170
|
+
margin-bottom: 16px;
|
|
171
|
+
display: flex;
|
|
172
|
+
align-items: center;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.stu-name {
|
|
176
|
+
font-size: 13px;
|
|
177
|
+
font-weight: 500;
|
|
178
|
+
color: var(--text);
|
|
179
|
+
margin-bottom: 1px;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.stu-sub {
|
|
183
|
+
font-family: 'IBM Plex Mono', monospace;
|
|
184
|
+
font-size: 10px;
|
|
185
|
+
color: var(--dim);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.status-right {
|
|
189
|
+
margin-left: auto;
|
|
190
|
+
display: flex;
|
|
191
|
+
flex-direction: column;
|
|
192
|
+
align-items: flex-end;
|
|
193
|
+
gap: 5px;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.prog-wrap {
|
|
197
|
+
display: flex;
|
|
198
|
+
align-items: center;
|
|
199
|
+
gap: 7px;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.prog-track {
|
|
203
|
+
width: 72px;
|
|
204
|
+
height: 3px;
|
|
205
|
+
background: var(--muted);
|
|
206
|
+
border-radius: 2px;
|
|
207
|
+
overflow: hidden;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.prog-fill {
|
|
211
|
+
height: 100%;
|
|
212
|
+
background: var(--green);
|
|
213
|
+
border-radius: 2px;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.prog-text {
|
|
217
|
+
font-family: 'IBM Plex Mono', monospace;
|
|
218
|
+
font-size: 10px;
|
|
219
|
+
color: var(--dim);
|
|
220
|
+
white-space: nowrap;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.state-pill {
|
|
224
|
+
font-family: 'IBM Plex Mono', monospace;
|
|
225
|
+
font-size: 9px;
|
|
226
|
+
font-weight: 600;
|
|
227
|
+
letter-spacing: 0.08em;
|
|
228
|
+
text-transform: uppercase;
|
|
229
|
+
padding: 2px 7px;
|
|
230
|
+
border-radius: 10px;
|
|
231
|
+
background: var(--green-dim);
|
|
232
|
+
color: var(--green);
|
|
233
|
+
display: flex;
|
|
234
|
+
align-items: center;
|
|
235
|
+
gap: 4px;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.dot {
|
|
239
|
+
width: 5px; height: 5px;
|
|
240
|
+
border-radius: 50%;
|
|
241
|
+
background: var(--green);
|
|
242
|
+
animation: blink 2s ease-in-out infinite;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
@keyframes blink { 0%,100%{opacity:1} 50%{opacity:.3} }
|
|
246
|
+
|
|
247
|
+
.sec { margin-bottom: 12px; }
|
|
248
|
+
|
|
249
|
+
.sec-label {
|
|
250
|
+
font-family: 'IBM Plex Mono', monospace;
|
|
251
|
+
font-size: 9px;
|
|
252
|
+
font-weight: 600;
|
|
253
|
+
text-transform: uppercase;
|
|
254
|
+
letter-spacing: 0.12em;
|
|
255
|
+
color: var(--muted);
|
|
256
|
+
margin-bottom: 5px;
|
|
257
|
+
padding-left: 2px;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.cmd-list {
|
|
261
|
+
display: flex;
|
|
262
|
+
flex-direction: column;
|
|
263
|
+
gap: 2px;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.cmd {
|
|
267
|
+
display: flex;
|
|
268
|
+
flex-direction: column;
|
|
269
|
+
border-radius: 6px;
|
|
270
|
+
border: 1px solid transparent;
|
|
271
|
+
background: transparent;
|
|
272
|
+
transition: background 0.12s, border-color 0.12s;
|
|
273
|
+
overflow: hidden;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.cmd-row {
|
|
277
|
+
display: flex;
|
|
278
|
+
align-items: center;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.cmd.hi {
|
|
282
|
+
background: var(--green-glow);
|
|
283
|
+
border-color: var(--green-dim);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.cmd.open {
|
|
287
|
+
background: var(--surface2);
|
|
288
|
+
border-color: var(--border-hi);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
.cmd.hi.open {
|
|
292
|
+
background: rgba(74,222,128,0.11);
|
|
293
|
+
border-color: rgba(74,222,128,0.3);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.cmd-inner {
|
|
297
|
+
flex: 1;
|
|
298
|
+
padding: 10px 10px;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
.cmd-label {
|
|
302
|
+
font-size: 14px;
|
|
303
|
+
color: var(--text);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.cmd.hi .cmd-label {
|
|
307
|
+
font-weight: 500;
|
|
308
|
+
color: var(--green);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/* tooltip — click toggled */
|
|
312
|
+
.cmd-tip {
|
|
313
|
+
display: none;
|
|
314
|
+
left: 0; right: 0;
|
|
315
|
+
background: #19211e;
|
|
316
|
+
border-top: 1px solid var(--border-hi);
|
|
317
|
+
padding: 10px 12px 11px;
|
|
318
|
+
margin: 0 -1px;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
.cmd.open .cmd-tip { display: block; }
|
|
322
|
+
|
|
323
|
+
.tip-text {
|
|
324
|
+
font-size: 12px;
|
|
325
|
+
color: var(--dim);
|
|
326
|
+
line-height: 1.5;
|
|
327
|
+
margin-bottom: 7px;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
.tip-tools {
|
|
331
|
+
display: flex;
|
|
332
|
+
gap: 4px;
|
|
333
|
+
flex-wrap: wrap;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.tip-tool {
|
|
337
|
+
font-family: 'IBM Plex Mono', monospace;
|
|
338
|
+
font-size: 10px;
|
|
339
|
+
padding: 2px 6px;
|
|
340
|
+
background: var(--blue-dim);
|
|
341
|
+
color: var(--blue);
|
|
342
|
+
border-radius: 3px;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/* info toggle button */
|
|
346
|
+
.info-btn {
|
|
347
|
+
flex-shrink: 0;
|
|
348
|
+
width: 32px;
|
|
349
|
+
height: 32px;
|
|
350
|
+
margin: 0 4px 0 0;
|
|
351
|
+
background: transparent;
|
|
352
|
+
border: 1px solid transparent;
|
|
353
|
+
border-radius: 4px;
|
|
354
|
+
color: var(--muted);
|
|
355
|
+
cursor: pointer;
|
|
356
|
+
font-size: 14px;
|
|
357
|
+
display: flex;
|
|
358
|
+
align-items: center;
|
|
359
|
+
justify-content: center;
|
|
360
|
+
transition: all 0.12s;
|
|
361
|
+
position: relative;
|
|
362
|
+
z-index: 20;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
.info-btn:hover, .cmd.open .info-btn {
|
|
366
|
+
color: var(--dim);
|
|
367
|
+
border-color: var(--border-hi);
|
|
368
|
+
background: var(--surface2);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.copy-btn {
|
|
372
|
+
flex-shrink: 0;
|
|
373
|
+
font-family: 'IBM Plex Mono', monospace;
|
|
374
|
+
font-size: 15px;
|
|
375
|
+
font-weight: 500;
|
|
376
|
+
padding: 10px 18px;
|
|
377
|
+
margin: 6px 6px 6px 0;
|
|
378
|
+
background: transparent;
|
|
379
|
+
border: 1px solid var(--border-hi);
|
|
380
|
+
border-radius: 6px;
|
|
381
|
+
color: var(--dim);
|
|
382
|
+
cursor: pointer;
|
|
383
|
+
white-space: nowrap;
|
|
384
|
+
transition: all 0.12s;
|
|
385
|
+
position: relative;
|
|
386
|
+
z-index: 20;
|
|
387
|
+
min-width: 72px;
|
|
388
|
+
text-align: center;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
.copy-btn:active {
|
|
392
|
+
transform: scale(0.96);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
.copy-btn:hover {
|
|
396
|
+
background: var(--muted);
|
|
397
|
+
color: var(--text);
|
|
398
|
+
border-color: var(--dim);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
.copy-btn.ok {
|
|
402
|
+
background: var(--green-dim);
|
|
403
|
+
border-color: var(--green);
|
|
404
|
+
color: var(--green);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
.cmd.hi .copy-btn {
|
|
408
|
+
border-color: rgba(74,222,128,0.35);
|
|
409
|
+
color: var(--green);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
.div {
|
|
413
|
+
height: 1px;
|
|
414
|
+
background: var(--border);
|
|
415
|
+
margin: 4px 0 12px;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
.foot {
|
|
419
|
+
margin-top: 4px;
|
|
420
|
+
position: relative;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
.webapp-btn {
|
|
424
|
+
display: block;
|
|
425
|
+
width: 100%;
|
|
426
|
+
padding: 14px;
|
|
427
|
+
background: var(--surface);
|
|
428
|
+
border: 1px solid var(--border);
|
|
429
|
+
border-radius: 6px;
|
|
430
|
+
color: var(--dim);
|
|
431
|
+
font-family: 'IBM Plex Sans', sans-serif;
|
|
432
|
+
font-size: 15px;
|
|
433
|
+
font-weight: 500;
|
|
434
|
+
text-align: center;
|
|
435
|
+
cursor: pointer;
|
|
436
|
+
transition: background 0.12s, border-color 0.12s, color 0.12s;
|
|
437
|
+
text-decoration: none;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
.webapp-btn:active {
|
|
441
|
+
transform: scale(0.98);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
.webapp-btn:hover, .webapp-btn.open {
|
|
445
|
+
background: var(--surface2);
|
|
446
|
+
border-color: var(--border-hi);
|
|
447
|
+
color: var(--text);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
.webapp-tip {
|
|
451
|
+
display: none;
|
|
452
|
+
background: #19211e;
|
|
453
|
+
border: 1px solid var(--border-hi);
|
|
454
|
+
border-top: none;
|
|
455
|
+
border-radius: 0 0 6px 6px;
|
|
456
|
+
padding: 10px 12px;
|
|
457
|
+
font-size: 12px;
|
|
458
|
+
color: var(--dim);
|
|
459
|
+
line-height: 1.5;
|
|
460
|
+
margin-top: -1px;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
.webapp-wrap.open .webapp-tip { display: block; }
|
|
464
|
+
.webapp-wrap.open .webapp-btn {
|
|
465
|
+
border-radius: 6px 6px 0 0;
|
|
466
|
+
border-color: var(--border-hi);
|
|
467
|
+
background: var(--surface2);
|
|
468
|
+
color: var(--text);
|
|
469
|
+
}
|
|
470
|
+
</style>
|
|
471
|
+
</head>
|
|
472
|
+
<body>
|
|
473
|
+
|
|
474
|
+
<div class="hd">
|
|
475
|
+
<div class="brand">AI Uni</div>
|
|
476
|
+
<div class="session-badge">{{COURSE_CODE}} · S{{SEQ_NUM}} of {{TOTAL}}</div>
|
|
477
|
+
</div>
|
|
478
|
+
|
|
479
|
+
<div class="hint">Copy a command below and paste it into chat.</div>
|
|
480
|
+
|
|
481
|
+
<div class="status">
|
|
482
|
+
<div>
|
|
483
|
+
<div class="stu-name">{{STUDENT_NAME}}</div>
|
|
484
|
+
<div class="stu-sub">{{COURSE_TITLE}} · Session {{SEQ_NUM}}</div>
|
|
485
|
+
</div>
|
|
486
|
+
<div class="status-right">
|
|
487
|
+
<div class="state-pill"><div class="dot"></div>In progress</div>
|
|
488
|
+
<div class="prog-wrap">
|
|
489
|
+
<div class="prog-track"><div class="prog-fill" style="width: {{PROGRESS_PCT}}%"></div></div>
|
|
490
|
+
<div class="prog-text">{{COMPLETED}} / {{TOTAL}}</div>
|
|
491
|
+
</div>
|
|
492
|
+
</div>
|
|
493
|
+
</div>
|
|
494
|
+
|
|
495
|
+
<!-- Starting out -->
|
|
496
|
+
<div class="sec">
|
|
497
|
+
<div class="sec-label">Starting out</div>
|
|
498
|
+
<div class="cmd-list">
|
|
499
|
+
|
|
500
|
+
<div class="cmd hi">
|
|
501
|
+
<div class="cmd-row">
|
|
502
|
+
<div class="cmd-inner"><div class="cmd-label">Start session</div></div>
|
|
503
|
+
<button class="info-btn" onclick="tog(this)">?</button>
|
|
504
|
+
<button class="copy-btn" onclick="cp(this,\`Start my session\`)">Copy</button>
|
|
505
|
+
</div>
|
|
506
|
+
<div class="cmd-tip">
|
|
507
|
+
<div class="tip-text">Begins the guided session from where you left off. Use this if you just opened a new conversation.</div>
|
|
508
|
+
<div class="tip-tools"><span class="tip-tool">get_student_context</span><span class="tip-tool">get_current_assignment</span></div>
|
|
509
|
+
</div>
|
|
510
|
+
</div>
|
|
511
|
+
|
|
512
|
+
<div class="cmd">
|
|
513
|
+
<div class="cmd-row">
|
|
514
|
+
<div class="cmd-inner"><div class="cmd-label">Pick up where I left off</div></div>
|
|
515
|
+
<button class="info-btn" onclick="tog(this)">?</button>
|
|
516
|
+
<button class="copy-btn" onclick="cp(this,\`Pick up where I left off\`)">Copy</button>
|
|
517
|
+
</div>
|
|
518
|
+
<div class="cmd-tip">
|
|
519
|
+
<div class="tip-text">Restores your last saved note. Use this if you closed Claude mid-session and are returning.</div>
|
|
520
|
+
<div class="tip-tools"><span class="tip-tool">get_student_context</span></div>
|
|
521
|
+
</div>
|
|
522
|
+
</div>
|
|
523
|
+
|
|
524
|
+
</div>
|
|
525
|
+
</div>
|
|
526
|
+
|
|
527
|
+
<div class="div"></div>
|
|
528
|
+
|
|
529
|
+
<!-- Mid session -->
|
|
530
|
+
<div class="sec">
|
|
531
|
+
<div class="sec-label">Mid session</div>
|
|
532
|
+
<div class="cmd-list">
|
|
533
|
+
|
|
534
|
+
<div class="cmd">
|
|
535
|
+
<div class="cmd-row">
|
|
536
|
+
<div class="cmd-inner"><div class="cmd-label">What's my exercise?</div></div>
|
|
537
|
+
<button class="info-btn" onclick="tog(this)">?</button>
|
|
538
|
+
<button class="copy-btn" onclick="cp(this,\`What's my exercise?\`)">Copy</button>
|
|
539
|
+
</div>
|
|
540
|
+
<div class="cmd-tip">
|
|
541
|
+
<div class="tip-text">Shows the full exercise, format, and what done looks like. Pull this up before you start working.</div>
|
|
542
|
+
<div class="tip-tools"><span class="tip-tool">get_current_assignment</span></div>
|
|
543
|
+
</div>
|
|
544
|
+
</div>
|
|
545
|
+
|
|
546
|
+
<div class="cmd">
|
|
547
|
+
<div class="cmd-row">
|
|
548
|
+
<div class="cmd-inner"><div class="cmd-label">How will this be graded?</div></div>
|
|
549
|
+
<button class="info-btn" onclick="tog(this)">?</button>
|
|
550
|
+
<button class="copy-btn" onclick="cp(this,\`How will this be graded?\`)">Copy</button>
|
|
551
|
+
</div>
|
|
552
|
+
<div class="cmd-tip">
|
|
553
|
+
<div class="tip-text">Shows the exact rubric. Know these before you submit — Claude evaluates against each criterion specifically.</div>
|
|
554
|
+
<div class="tip-tools"><span class="tip-tool">get_rubric</span></div>
|
|
555
|
+
</div>
|
|
556
|
+
</div>
|
|
557
|
+
|
|
558
|
+
<div class="cmd">
|
|
559
|
+
<div class="cmd-row">
|
|
560
|
+
<div class="cmd-inner"><div class="cmd-label">Save and stop</div></div>
|
|
561
|
+
<button class="info-btn" onclick="tog(this)">?</button>
|
|
562
|
+
<button class="copy-btn" onclick="cp(this,\`Save and stop for now\`)">Copy</button>
|
|
563
|
+
</div>
|
|
564
|
+
<div class="cmd-tip">
|
|
565
|
+
<div class="tip-text">Saves a note so you can resume here later. Always do this before closing Claude mid-session.</div>
|
|
566
|
+
<div class="tip-tools"><span class="tip-tool">save_session_note</span></div>
|
|
567
|
+
</div>
|
|
568
|
+
</div>
|
|
569
|
+
|
|
570
|
+
</div>
|
|
571
|
+
</div>
|
|
572
|
+
|
|
573
|
+
<div class="div"></div>
|
|
574
|
+
|
|
575
|
+
<!-- Wrapping up -->
|
|
576
|
+
<div class="sec">
|
|
577
|
+
<div class="sec-label">Wrapping up</div>
|
|
578
|
+
<div class="cmd-list">
|
|
579
|
+
|
|
580
|
+
<div class="cmd">
|
|
581
|
+
<div class="cmd-row">
|
|
582
|
+
<div class="cmd-inner"><div class="cmd-label">Check my work</div></div>
|
|
583
|
+
<button class="info-btn" onclick="tog(this)">?</button>
|
|
584
|
+
<button class="copy-btn" onclick="cp(this,\`Check my work against the rubric\`)">Copy</button>
|
|
585
|
+
</div>
|
|
586
|
+
<div class="cmd-tip">
|
|
587
|
+
<div class="tip-text">Claude reviews your work against the rubric and gives specific feedback. Do this before marking complete.</div>
|
|
588
|
+
<div class="tip-tools"><span class="tip-tool">get_rubric</span></div>
|
|
589
|
+
</div>
|
|
590
|
+
</div>
|
|
591
|
+
|
|
592
|
+
<div class="cmd hi">
|
|
593
|
+
<div class="cmd-row">
|
|
594
|
+
<div class="cmd-inner"><div class="cmd-label">Mark complete</div></div>
|
|
595
|
+
<button class="info-btn" onclick="tog(this)">?</button>
|
|
596
|
+
<button class="copy-btn" onclick="cp(this,\`Mark this session complete\`)">Copy</button>
|
|
597
|
+
</div>
|
|
598
|
+
<div class="cmd-tip">
|
|
599
|
+
<div class="tip-text">Records completion and unlocks your next session. Only after Claude confirms your work passes. Then confirm in the web app.</div>
|
|
600
|
+
<div class="tip-tools"><span class="tip-tool">submit_session_complete</span><span class="tip-tool">get_next_assignment</span></div>
|
|
601
|
+
</div>
|
|
602
|
+
</div>
|
|
603
|
+
|
|
604
|
+
</div>
|
|
605
|
+
</div>
|
|
606
|
+
|
|
607
|
+
<div class="div"></div>
|
|
608
|
+
|
|
609
|
+
<!-- Between sessions -->
|
|
610
|
+
<div class="sec">
|
|
611
|
+
<div class="sec-label">Between sessions</div>
|
|
612
|
+
<div class="cmd-list">
|
|
613
|
+
|
|
614
|
+
<div class="cmd">
|
|
615
|
+
<div class="cmd-row">
|
|
616
|
+
<div class="cmd-inner"><div class="cmd-label">What's next?</div></div>
|
|
617
|
+
<button class="info-btn" onclick="tog(this)">?</button>
|
|
618
|
+
<button class="copy-btn" onclick="cp(this,\`What's next?\`)">Copy</button>
|
|
619
|
+
</div>
|
|
620
|
+
<div class="cmd-tip">
|
|
621
|
+
<div class="tip-text">Previews your next session without advancing. Good for planning.</div>
|
|
622
|
+
<div class="tip-tools"><span class="tip-tool">get_next_assignment</span></div>
|
|
623
|
+
</div>
|
|
624
|
+
</div>
|
|
625
|
+
|
|
626
|
+
<div class="cmd">
|
|
627
|
+
<div class="cmd-row">
|
|
628
|
+
<div class="cmd-inner"><div class="cmd-label">My progress</div></div>
|
|
629
|
+
<button class="info-btn" onclick="tog(this)">?</button>
|
|
630
|
+
<button class="copy-btn" onclick="cp(this,\`Show my full course progress\`)">Copy</button>
|
|
631
|
+
</div>
|
|
632
|
+
<div class="cmd-tip">
|
|
633
|
+
<div class="tip-text">All sessions — done, active, upcoming — with your notes. Should match the web app.</div>
|
|
634
|
+
<div class="tip-tools"><span class="tip-tool">get_student_context</span></div>
|
|
635
|
+
</div>
|
|
636
|
+
</div>
|
|
637
|
+
|
|
638
|
+
</div>
|
|
639
|
+
</div>
|
|
640
|
+
|
|
641
|
+
<div class="foot">
|
|
642
|
+
<div class="webapp-wrap" id="webappWrap">
|
|
643
|
+
<a class="webapp-btn" href="https://app.aiuni.tech" target="_blank" onclick="togWebapp(event)">
|
|
644
|
+
Open web app
|
|
645
|
+
</a>
|
|
646
|
+
<div class="webapp-tip">Check session status, confirm completions, and view your portfolio. If a session isn't marked done here, record it from the app — you don't need Claude for that.</div>
|
|
647
|
+
</div>
|
|
648
|
+
</div>
|
|
649
|
+
|
|
650
|
+
<script>
|
|
651
|
+
function tog(infoBtn) {
|
|
652
|
+
const cmd = infoBtn.closest('.cmd');
|
|
653
|
+
cmd.classList.toggle('open');
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
function togWebapp(e) {
|
|
657
|
+
const wrap = document.getElementById('webappWrap');
|
|
658
|
+
if (wrap.classList.contains('open')) {
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
e.preventDefault();
|
|
662
|
+
wrap.classList.add('open');
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
function cp(btn, text) {
|
|
666
|
+
navigator.clipboard.writeText(text).then(() => {
|
|
667
|
+
const p = btn.textContent;
|
|
668
|
+
btn.textContent = '✓';
|
|
669
|
+
btn.classList.add('ok');
|
|
670
|
+
setTimeout(() => { btn.textContent = p; btn.classList.remove('ok'); }, 1400);
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
</script>
|
|
674
|
+
</body>
|
|
675
|
+
</html>`;
|
|
676
|
+
const server = new McpServer({ name: "aiuni-mcp", version: "0.1.4" }, { instructions: TUTOR_INSTRUCTIONS });
|
|
97
677
|
// ---------------------------------------------------------------------------
|
|
98
678
|
// Helpers
|
|
99
679
|
// ---------------------------------------------------------------------------
|
|
@@ -216,6 +796,41 @@ server.tool("get_student_context", "Returns the student's profile, enrollments,
|
|
|
216
796
|
}
|
|
217
797
|
});
|
|
218
798
|
// ---------------------------------------------------------------------------
|
|
799
|
+
// Tool: get_session_panel
|
|
800
|
+
// ---------------------------------------------------------------------------
|
|
801
|
+
server.tool("get_session_panel", "Returns an HTML session control panel populated with the student's current progress. Render this as an artifact at the start of every conversation.", {}, async () => {
|
|
802
|
+
try {
|
|
803
|
+
const studentId = await getStudentId();
|
|
804
|
+
// Get student name
|
|
805
|
+
const { data: student } = await supabase
|
|
806
|
+
.from("students")
|
|
807
|
+
.select("name")
|
|
808
|
+
.eq("id", studentId)
|
|
809
|
+
.single();
|
|
810
|
+
if (!student)
|
|
811
|
+
return errorResult("Student not found");
|
|
812
|
+
const next = await findNextSession(studentId);
|
|
813
|
+
if (!next) {
|
|
814
|
+
return textResult('RENDER THE FOLLOWING HTML AS AN ARTIFACT (title: "AI Uni — Session Panel", type: HTML). Do not modify the HTML. Display it exactly as-is:\n\n' +
|
|
815
|
+
`<html><body style="background:#0d0f0e;color:#dde8e1;font-family:sans-serif;display:flex;align-items:center;justify-content:center;min-height:100vh;"><div style="text-align:center;"><h1>All courses complete!</h1><p style="color:#4ade80;font-size:1.2em;">Congratulations, ${student.name}!</p></div></body></html>`);
|
|
816
|
+
}
|
|
817
|
+
const completed = next.sequence_num - 1;
|
|
818
|
+
const pct = Math.round((completed / next.total_sessions) * 100);
|
|
819
|
+
const html = SESSION_PANEL_HTML
|
|
820
|
+
.replace(/\{\{STUDENT_NAME\}\}/g, student.name)
|
|
821
|
+
.replace(/\{\{COURSE_CODE\}\}/g, next.course_code)
|
|
822
|
+
.replace(/\{\{COURSE_TITLE\}\}/g, next.course_title)
|
|
823
|
+
.replace(/\{\{SEQ_NUM\}\}/g, String(next.sequence_num))
|
|
824
|
+
.replace(/\{\{TOTAL\}\}/g, String(next.total_sessions))
|
|
825
|
+
.replace(/\{\{COMPLETED\}\}/g, String(completed))
|
|
826
|
+
.replace(/\{\{PROGRESS_PCT\}\}/g, String(pct));
|
|
827
|
+
return textResult('RENDER THE FOLLOWING HTML AS AN ARTIFACT (title: "AI Uni — Session Panel", type: HTML). Do not modify the HTML. Display it exactly as-is.\n\nNote: the panel shows your progress at conversation start. To see updated progress after completing a session, start a new conversation.\n\n' + html);
|
|
828
|
+
}
|
|
829
|
+
catch (err) {
|
|
830
|
+
return errorResult(err.message);
|
|
831
|
+
}
|
|
832
|
+
});
|
|
833
|
+
// ---------------------------------------------------------------------------
|
|
219
834
|
// Tool: get_current_assignment
|
|
220
835
|
// ---------------------------------------------------------------------------
|
|
221
836
|
server.tool("get_current_assignment", "Returns the full session brief for the student's current (next incomplete) assignment, including overview, learning objectives, topics, and exercise details.", {}, async () => {
|
package/package.json
CHANGED
|
@@ -44,13 +44,11 @@
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
.brand {
|
|
47
|
-
font-family: 'IBM Plex
|
|
48
|
-
font-size:
|
|
47
|
+
font-family: 'IBM Plex Sans', sans-serif;
|
|
48
|
+
font-size: 14px;
|
|
49
49
|
font-weight: 600;
|
|
50
|
-
color: var(--
|
|
51
|
-
letter-spacing: 0.04em;
|
|
50
|
+
color: var(--text);
|
|
52
51
|
}
|
|
53
|
-
.brand em { color: var(--green); font-style: normal; }
|
|
54
52
|
|
|
55
53
|
.session-badge {
|
|
56
54
|
font-family: 'IBM Plex Mono', monospace;
|
|
@@ -62,6 +60,12 @@
|
|
|
62
60
|
padding: 3px 8px;
|
|
63
61
|
}
|
|
64
62
|
|
|
63
|
+
.hint {
|
|
64
|
+
font-size: 11px;
|
|
65
|
+
color: var(--dim);
|
|
66
|
+
margin-bottom: 10px;
|
|
67
|
+
}
|
|
68
|
+
|
|
65
69
|
.status {
|
|
66
70
|
background: var(--surface);
|
|
67
71
|
border: 1px solid var(--border);
|
|
@@ -373,10 +377,12 @@
|
|
|
373
377
|
<body>
|
|
374
378
|
|
|
375
379
|
<div class="hd">
|
|
376
|
-
<div class="brand">
|
|
380
|
+
<div class="brand">AI Uni</div>
|
|
377
381
|
<div class="session-badge">CORE-01 · S1 of 10</div>
|
|
378
382
|
</div>
|
|
379
383
|
|
|
384
|
+
<div class="hint">Copy a command below and paste it into chat.</div>
|
|
385
|
+
|
|
380
386
|
<div class="status">
|
|
381
387
|
<div>
|
|
382
388
|
<div class="stu-name">Jon</div>
|
|
@@ -398,12 +404,12 @@
|
|
|
398
404
|
|
|
399
405
|
<div class="cmd hi">
|
|
400
406
|
<div class="cmd-row">
|
|
401
|
-
<div class="cmd-inner"><div class="cmd-label">
|
|
407
|
+
<div class="cmd-inner"><div class="cmd-label">Start session</div></div>
|
|
402
408
|
<button class="info-btn" onclick="tog(this)">?</button>
|
|
403
|
-
<button class="copy-btn" onclick="cp(this,`
|
|
409
|
+
<button class="copy-btn" onclick="cp(this,`Start my session`)">Copy</button>
|
|
404
410
|
</div>
|
|
405
411
|
<div class="cmd-tip">
|
|
406
|
-
<div class="tip-text">
|
|
412
|
+
<div class="tip-text">Begins the guided session from where you left off. Use this if you just opened a new conversation.</div>
|
|
407
413
|
<div class="tip-tools"><span class="tip-tool">get_student_context</span><span class="tip-tool">get_current_assignment</span></div>
|
|
408
414
|
</div>
|
|
409
415
|
</div>
|
|
@@ -539,7 +545,7 @@
|
|
|
539
545
|
|
|
540
546
|
<div class="foot">
|
|
541
547
|
<div class="webapp-wrap" id="webappWrap">
|
|
542
|
-
<a class="webapp-btn" href="https://app.
|
|
548
|
+
<a class="webapp-btn" href="https://app.aiuni.tech" target="_blank" onclick="togWebapp(event)">
|
|
543
549
|
Open web app
|
|
544
550
|
</a>
|
|
545
551
|
<div class="webapp-tip">Check session status, confirm completions, and view your portfolio. If a session isn't marked done here, record it from the app — you don't need Claude for that.</div>
|
package/prompts/tutor-system.md
CHANGED
|
@@ -8,7 +8,7 @@ You are the AI Uni tutor — a Socratic learning partner for students in AI Uni,
|
|
|
8
8
|
|
|
9
9
|
## First Action (Every Conversation)
|
|
10
10
|
|
|
11
|
-
**Before saying anything**, call `get_student_context`.
|
|
11
|
+
**Before saying anything**, call `get_student_context` and `get_session_panel`. The first tells you who the student is and where they are in the curriculum. The second returns an HTML session panel — render it as an artifact (title: "AI Uni — Session Panel", type: HTML) exactly as returned, with no modifications.
|
|
12
12
|
|
|
13
13
|
After reviewing context, greet the student by name and summarize where they are:
|
|
14
14
|
- If they have a session in progress, offer to pick up where they left off.
|
|
@@ -47,11 +47,12 @@ A typical tutoring session follows this arc:
|
|
|
47
47
|
|
|
48
48
|
## Using Your Tools
|
|
49
49
|
|
|
50
|
-
You have
|
|
50
|
+
You have seven MCP tools. Use them proactively — don't wait for the student to ask.
|
|
51
51
|
|
|
52
52
|
| Tool | When to Use |
|
|
53
53
|
|------|-------------|
|
|
54
54
|
| `get_student_context` | Start of every conversation. No exceptions. |
|
|
55
|
+
| `get_session_panel` | Start of every conversation, alongside `get_student_context`. Render the returned HTML as an artifact. |
|
|
55
56
|
| `get_current_assignment` | After context check, to load the session brief. |
|
|
56
57
|
| `get_rubric` | Before evaluating student work. Never evaluate without it. |
|
|
57
58
|
| `submit_session_complete` | Only when all acceptance criteria are met. Never premature. |
|