Skip to main content
Glama

mcp-voice-hooks

index.html13.6 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Voice Mode for Claude Code</title> <style> body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; background-color: #f5f5f5; } .container { background: white; border-radius: 12px; padding: 24px; box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1); } h1 { color: #333; margin-bottom: 8px; } .subtitle { color: #666; margin-bottom: 24px; } .input-section { margin-bottom: 24px; } .input-group { display: flex; gap: 12px; margin-bottom: 16px; } #utteranceInput { flex: 1; padding: 12px; border: 2px solid #ddd; border-radius: 8px; font-size: 16px; } #utteranceInput:focus { outline: none; border-color: #007AFF; } #sendBtn { background: #007AFF; color: white; border: none; padding: 12px 24px; border-radius: 8px; font-size: 16px; cursor: pointer; } #sendBtn:hover { background: #0056CC; } #sendBtn:disabled { background: #ccc; cursor: not-allowed; } .utterances-section h3 { color: #333; margin-bottom: 16px; } .utterances-list { max-height: 400px; overflow-y: auto; border: 1px solid #ddd; border-radius: 8px; } .utterance-item { padding: 12px 16px; border-bottom: 1px solid #eee; display: flex; justify-content: space-between; align-items: center; } .utterance-item:last-child { border-bottom: none; } .utterance-text { flex: 1; margin-right: 12px; } .utterance-meta { font-size: 12px; color: #666; text-align: right; } .utterance-status { display: inline-block; padding: 2px 8px; border-radius: 12px; font-size: 11px; font-weight: bold; margin-top: 4px; } .status-pending { background: #FFF3CD; color: #856404; } .status-delivered { background: #D1ECF1; color: #0C5460; } .refresh-btn { background: #6C757D; color: white; border: none; padding: 8px 16px; border-radius: 6px; font-size: 14px; cursor: pointer; margin-left: 12px; } .refresh-btn:hover { background: #545B62; } .empty-state { text-align: center; color: #666; padding: 12px 16px; font-style: italic; } .voice-controls { display: flex; gap: 12px; align-items: center; margin-bottom: 16px; } #listenBtn { background: #28A745; color: white; border: none; padding: 12px 24px; border-radius: 8px; font-size: 16px; cursor: pointer; display: flex; align-items: center; gap: 8px; } #listenBtn:hover { background: #218838; } #listenBtn.listening { background: #DC3545; } #listenBtn.listening:hover { background: #C82333; } #listenBtn:disabled { background: #ccc; cursor: not-allowed; } .listening-indicator { display: none; align-items: center; gap: 8px; color: #DC3545; font-weight: 500; } .listening-indicator.active { display: flex; } .listening-dot { width: 8px; height: 8px; background: #DC3545; border-radius: 50%; animation: pulse 1.5s infinite; } @keyframes pulse { 0% { opacity: 1; } 50% { opacity: 0.3; } 100% { opacity: 1; } } .interim-text { padding: 12px; background: #F8F9FA; border: 1px solid #DEE2E6; border-radius: 8px; margin-bottom: 16px; font-style: italic; color: #6C757D; min-height: 44px; /* Maintain minimum height to prevent collapse */ max-height: 120px; /* Prevent excessive growth */ overflow-y: auto; /* Add scroll if content is too long */ transition: color 0.2s ease-in-out; } .interim-text.active { color: #333; /* Darker color for actual speech */ font-style: normal; } .mic-icon { width: 16px; height: 16px; fill: currentColor; } .tts-settings { background: #f8f9fa; padding: 12px; border-radius: 8px; margin-bottom: 24px; } .tts-settings h4 { margin-top: 0; margin-bottom: 0; color: #333; } .tts-controls { display: flex; gap: 16px; align-items: center; flex-wrap: wrap; width: 100%; box-sizing: border-box; margin-top: 16px; } .tts-control { display: flex; align-items: center; gap: 8px; } .tts-control label { font-size: 14px; color: #666; } .tts-control select { padding: 6px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px; width: 100%; box-sizing: border-box; overflow: hidden; text-overflow: ellipsis; } .tts-control input { padding: 6px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px; box-sizing: border-box; } .tts-test-btn { background: #6C757D; color: white; border: none; padding: 6px 12px; border-radius: 4px; font-size: 14px; cursor: pointer; } .tts-test-btn:hover { background: #545B62; } .rate-warning, .system-voice-info { font-size: 12px; padding: 8px 12px; border-radius: 6px; margin: 8px 0; display: flex; align-items: center; gap: 8px; } .rate-warning { background: #fff3cd; color: #856404; border: 1px solid #ffeaa7; } .system-voice-info { background: #d1ecf1; color: #0c5460; border: 1px solid #bee5eb; } .system-voice-info a { color: #0c5460; font-weight: bold; } .warning-icon, .info-icon { font-size: 16px; } .info-message { background: #d1ecf1; border: 1px solid #bee5eb; border-radius: 8px; margin-bottom: 16px; } .info-message .empty-state { color: #0c5460; padding: 20px; font-style: normal; } /* Toggle switch styles */ .switch { position: relative; display: inline-block; width: 50px; height: 26px; } .switch input { opacity: 0; width: 0; height: 0; } .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; transition: .3s; border-radius: 26px; } .slider:before { position: absolute; content: ""; height: 18px; width: 18px; left: 4px; bottom: 4px; background-color: white; transition: .3s; border-radius: 50%; } input:checked+.slider { background-color: #007AFF; } input:checked+.slider:before { transform: translateX(24px); } </style> </head> <body> <div class="container"> <h1>Voice Mode for Claude Code</h1> <div class="input-section"> <div class="voice-controls"> <button id="listenBtn"> <svg class="mic-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M12 1C10.34 1 9 2.34 9 4V12C9 13.66 10.34 15 12 15C13.66 15 15 13.66 15 12V4C15 2.34 13.66 1 12 1ZM19 12C19 15.53 16.39 18.44 13 18.93V22H11V18.93C7.61 18.44 5 15.53 5 12H7C7 14.76 9.24 17 12 17C14.76 17 17 14.76 17 12H19Z" /> </svg> <span id="listenBtnText">Start Listening</span> </button> <div class="listening-indicator" id="listeningIndicator"> <div class="listening-dot"></div> <span>Listening...</span> </div> </div> <div class="interim-text" id="interimText">Start speaking and your words will appear here...</div> </div> <div class="tts-settings"> <div style="display: flex; justify-content: space-between; align-items: center;"> <h4>Allow Claude to speak back to you</h4> <label class="switch"> <input type="checkbox" id="voiceResponsesToggle"> <span class="slider"></span> </label> </div> <div class="tts-controls" id="voiceOptions" style="display: none;"> <div class="tts-control"> <label for="languageSelect">Language:</label> <select id="languageSelect"> <option value="en-US">Loading languages...</option> </select> </div> <div class="tts-control"> <label for="voiceSelect">Voice:</label> <select id="voiceSelect"> <option value="system">Mac System Voice</option> <optgroup label="Browser Voices (Cloud)" id="cloudVoicesGroup"> </optgroup> <optgroup label="Browser Voices (Local)" id="localVoicesGroup"> </optgroup> </select> </div> <div id="systemVoiceInfo" class="system-voice-info" style="display: none;"> <span class="info-icon">ℹ️</span> <span class="info-text">You can download high quality voices in your Mac settings app. See the <a href="https://github.com/johnmatthewtennant/mcp-voice-hooks?tab=readme-ov-file#voice-responses" target="_blank">README</a></span> </div> <div id="rateWarning" class="rate-warning" style="display: none;"> <span class="warning-icon">⚠️</span> <span class="warning-text">Google voices may not respond well to rate adjustments</span> </div> <div class="tts-control"> <label for="speechRate">Speaking Rate:</label> <input type="range" id="speechRate" min="0.5" max="5" step="0.1" value="1"> <input type="number" id="speechRateInput" min="0.5" max="5" step="0.1" value="1"> </div> <button class="tts-test-btn" id="testTTSBtn">Test Voice</button> </div> </div> <div class="utterances-section"> <h3> Recent Utterances <button class="refresh-btn" id="refreshBtn">Refresh</button> <button class="refresh-btn" id="clearAllBtn" style="background: #DC3545; margin-left: 8px;">Clear All</button> </h3> <div class="info-message" id="infoMessage" style="display: none;"> <div class="empty-state">You need to send one message in the Claude code CLI to start voice interaction </div> </div> <div class="utterances-list" id="utterancesList"> <div class="empty-state">Nothing yet.</div> </div> </div> </div> <script src="app.js"></script> </body> </html>

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/johnmatthewtennant/mcp-voice-hooks'

If you have feedback or need assistance with the MCP directory API, please join our Discord server