Global State:
let session: TranscriptionSession | null = null; // Line 112 in mcp-server.tsSession Creation (start_transcription):
const filename = (args?.outputFile as string) || generateTimestampedFilename();
const outputFile = join(OUTFILE_DIR, filename);
session = new TranscriptionSession(
customAudioConfig,
transcriptionConfig,
outputFile, // <-- Bound to specific file
statusChangeCallback,
VERSION
);Each Session Contains:
TranscriptManagerwith specificoutfilepath- All operations (read/write/clear) use
this.outfile getTranscriptPath()returns the session's specific file
| Operation | File Access Method | Isolation Status |
|---|---|---|
start_transcription |
Creates new session with unique timestamped filename | ✅ Isolated |
get_status |
Reads from session.getStatus() (in-memory) |
✅ Isolated |
get_transcript |
Reads from session.getTranscript() → this.outfile |
✅ Isolated |
clear_transcript |
Deletes/recreates session → this.outfile |
✅ Isolated |
cleanup_transcript |
Gets path from session.getTranscriptPath() |
✅ Isolated |
transcript://current resource |
Reads from session.getTranscriptPath() |
✅ Isolated |
Problem:
case "stop_transcription": {
// ...
await session.stop();
// ❌ session variable is NOT set to null!
// The stopped session remains in memory
return { /* success response */ };
}Impact:
- After
stop_transcription, the session remains in memory - Subsequent calls to
get_transcript,get_status,clear_transcriptwill access the STOPPED session's transcript - User might think they're starting fresh but still seeing old data
Scenario:
1. start_transcription → creates session with transcript_2025-10-04_10-00-00.md
2. [User records for 5 minutes]
3. stop_transcription → stops session BUT session variable still points to it
4. get_transcript → ❌ Returns old transcript from stopped session!
5. start_transcription → ✅ Blocked because session != null
Problem:
The transcript://current resource doesn't check if session is running:
if (!session) {
return "No active transcription session";
}
// ❌ Doesn't check if session.getStatus().isRunning
const filePath = session.getTranscriptPath();Impact:
- After stopping, the resource will still show the old transcript
- Misleading behavior - "current" implies active
- File-level isolation: Each
TranscriptionSessionbinds to ONE specific file path - No cross-contamination: Operations always use
this.outfilefromTranscriptManager - Timestamped filenames: Default behavior creates unique files per session
- Cleanup works:
cleanup_transcriptproperly deletes the session's file
case "stop_transcription": {
// ...
await session.stop();
// ✅ Clear reference so future operations don't access stopped session
session = null;
return { /* success response */ };
}Add helper function:
function hasActiveSession(): boolean {
return session !== null && session.getStatus().isRunning;
}Use in operations:
case "get_transcript": {
if (!hasActiveSession()) {
return createErrorResponse("No active transcription session");
}
// ...
}if (!session || !session.getStatus().isRunning) {
return {
contents: [{
uri,
mimeType: "text/plain",
text: "No active transcription session. Use start_transcription to begin."
}]
};
}Add tests for:
- Stop → get_transcript should error (not return old data)
- Stop → start new session → get_transcript should return NEW transcript
- Stop → resource read should return "no active session"
- Cleanup → all references cleared
- Multiple start/stop cycles don't leak memory or cross-contaminate
Current State: Session isolation is ARCHITECTURALLY SOUND but has OPERATIONAL ISSUES with stopped sessions remaining accessible.
Risk Level: MEDIUM - No data corruption between concurrent sessions (impossible with current design), but confusing behavior after stop.
Action: Implement fixes to clear session reference on stop and add state checks.