We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/a2345sooted/whats-for-dinner'
If you have feedback or need assistance with the MCP directory API, please join our Discord server
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Dinner Choice</title>
<style>
html {
height: 100%;
-webkit-text-size-adjust: 100%;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background-color: transparent;
color: #1f2937;
margin: 0;
padding: 0;
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-webkit-flex-direction: column;
flex-direction: column;
min-height: 100vh;
min-height: -webkit-fill-available;
-webkit-overflow-scrolling: touch;
}
.container {
-webkit-box-flex: 1;
-webkit-flex: 1;
flex: 1;
width: 100%;
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-webkit-flex-direction: column;
flex-direction: column;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
padding: 16px;
padding-top: calc(16px + env(safe-area-inset-top));
padding-bottom: calc(16px + env(safe-area-inset-bottom));
box-sizing: border-box;
}
.card {
background: white;
border-radius: 12px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
padding: 24px;
width: 100%;
max-width: 800px;
text-align: center;
box-sizing: border-box;
}
.full-screen-spin {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: #f3f4f6;
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-webkit-flex-direction: column;
flex-direction: column;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
-webkit-box-pack: start;
-webkit-justify-content: flex-start;
justify-content: flex-start;
z-index: 100;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
padding: 20px 16px;
padding-top: calc(40px + env(safe-area-inset-top));
padding-bottom: calc(40px + env(safe-area-inset-bottom));
}
/* Center content if it fits */
@media (min-height: 400px) {
.full-screen-spin {
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
padding-top: calc(20px + env(safe-area-inset-top));
}
}
h1 {
font-size: 1.5rem;
margin: 0 0 8px 0;
color: #111827;
}
.description {
color: #4b5563;
line-height: 1.4;
margin-top: 0;
margin-bottom: 8px;
font-size: 0.95rem;
}
.cycling-container {
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
width: 100%;
}
#cycling-text {
font-size: 3.5rem;
font-weight: 800;
color: #3b82f6;
text-align: center;
padding: 12px 20px;
-webkit-transition: all 0.2s ease-out;
transition: all 0.2s ease-out;
word-break: break-word;
max-width: 90%;
min-height: 1.2em;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 0;
}
@media (max-width: 480px) {
#cycling-text {
font-size: 2.5rem;
padding: 10px;
margin-bottom: 0;
}
h1 {
font-size: 1.25rem;
}
.card {
padding: 16px;
}
.btn {
width: 44px;
height: 44px;
}
.description {
font-size: 0.9rem;
margin-top: 0;
margin-bottom: 8px;
}
.full-screen-spin {
padding-top: calc(20px + env(safe-area-inset-top));
padding-bottom: calc(20px + env(safe-area-inset-bottom));
}
}
.cycling-text-change {
-webkit-transform: scale(1.1);
transform: scale(1.1);
opacity: 0.8;
}
.cta-container {
display: none;
}
.button-group {
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-webkit-flex-direction: row;
flex-direction: row;
gap: 16px;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
margin-top: 12px;
width: 100%;
}
.btn {
position: relative;
width: 48px;
height: 48px;
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
border-radius: 50%;
cursor: pointer;
-webkit-transition: all 0.2s;
transition: all 0.2s;
border: none;
color: white;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0.1);
-webkit-appearance: none;
padding: 0;
}
/* Custom Tooltip */
.btn::after {
content: attr(data-tooltip);
position: absolute;
bottom: 100%;
left: 50%;
-webkit-transform: translateX(-50%) translateY(-8px);
transform: translateX(-50%) translateY(-8px);
background: rgba(0, 0, 0, 0.8);
color: white;
padding: 4px 8px;
border-radius: 4px;
font-size: 0.75rem;
white-space: nowrap;
opacity: 0;
pointer-events: none;
-webkit-transition: all 0.2s;
transition: all 0.2s;
z-index: 10;
font-weight: 500;
}
.btn:hover::after {
opacity: 1;
-webkit-transform: translateX(-50%) translateY(-12px);
transform: translateX(-50%) translateY(-12px);
}
@media (hover: none) {
.btn::after {
display: none;
}
}
.btn:hover {
opacity: 0.9;
-webkit-transform: translateY(-1px);
transform: translateY(-1px);
}
.btn:active {
-webkit-transform: scale(0.98);
transform: scale(0.98);
}
.btn-recipes {
background: #10b981; /* green */
}
.btn-directions {
background: #3b82f6; /* blue */
}
.btn-restaurants {
background: #3b82f6; /* blue */
}
.btn-spin-again {
background: #f59e0b; /* yellow */
color: #1f2937;
}
/* Loading Spinner */
.spinner-container {
display: -webkit-box;
display: -webkit-flex;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-webkit-flex-direction: column;
flex-direction: column;
-webkit-box-align: center;
-webkit-align-items: center;
align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
justify-content: center;
gap: 16px;
}
.spinner {
width: 40px;
height: 40px;
border: 4px solid #f3f4f6;
border-top: 4px solid #3b82f6;
border-radius: 50%;
-webkit-animation: spin 1s linear infinite;
animation: spin 1s linear infinite;
}
@-webkit-keyframes spin {
0% { -webkit-transform: rotate(0deg); }
100% { -webkit-transform: rotate(360deg); }
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.loading-text {
color: #6b7280;
font-size: 0.875rem;
font-weight: 500;
}
</style>
</head>
<body>
<div id="spin-overlay" class="full-screen-spin">
<div class="cycling-container">
<div id="cycling-text">Waiting for options...</div>
</div>
<div id="post-spin-content" style="display: none; width: 100%; max-width: 600px; text-align: center; padding: 0 20px; box-sizing: border-box;">
<p id="result-description" class="description"></p>
<div class="button-group">
<button id="btn-recipes" class="btn btn-recipes" title="Find me recipes for this" data-tooltip="Recipes">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"></path><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"></path></svg>
</button>
<button id="btn-directions" class="btn btn-directions" title="Get directions" data-tooltip="Directions" style="display: none;">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="3 11 22 2 13 21 11 13 3 11"></polygon></svg>
</button>
<button id="btn-restaurants" class="btn btn-restaurants" title="Find me restaurants for this" data-tooltip="Restaurants">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"></path><circle cx="12" cy="10" r="3"></circle></svg>
</button>
<button id="btn-spin-again" class="btn btn-spin-again" title="Spin Again" data-tooltip="Spin Again">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M23 4v6h-6"></path><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path></svg>
</button>
</div>
</div>
</div>
<div class="container">
<div id="initial-loading">
<div id="spinner-view" class="spinner-container">
<div class="spinner"></div>
<div class="loading-text">Preparing options...</div>
</div>
</div>
</div>
<script>
let isSpinning = false;
let hasFinished = false;
let cachedToolOutput = null;
const startAnimation = () => {
if (!cachedToolOutput || isSpinning || hasFinished) return;
isSpinning = true;
const { options } = cachedToolOutput;
// Shuffle options first
const shuffledOptions = [...options].sort(() => Math.random() - 0.5);
// If we have many options, we can cycle through more of them to make it look better
// but we'll stop on one of the first few in the shuffled list or just keep it as is.
const spinOverlay = document.getElementById('spin-overlay');
const initialLoading = document.getElementById('initial-loading');
const cyclingText = document.getElementById('cycling-text');
const postSpinContent = document.getElementById('post-spin-content');
initialLoading.style.display = 'none';
spinOverlay.style.display = '-webkit-flex';
spinOverlay.style.display = 'flex';
postSpinContent.style.display = 'none';
cyclingText.style.webkitTransform = 'scale(1)';
cyclingText.style.transform = 'scale(1)';
cyclingText.style.color = '#3b82f6';
let currentIndex = 0;
const cycleInterval = 100; // ms
// Set a timeout for random value between 3.00 and 5.00 seconds for a better "full" feel
const totalDuration = Math.floor(Math.random() * 2001) + 3000;
const iterations = totalDuration / cycleInterval;
let currentIteration = 0;
const runCycle = () => {
cyclingText.textContent = shuffledOptions[currentIndex].name;
cyclingText.classList.add('cycling-text-change');
setTimeout(() => cyclingText.classList.remove('cycling-text-change'), 50);
const nextIndex = (currentIndex + 1) % shuffledOptions.length;
currentIteration++;
if (currentIteration < iterations) {
currentIndex = nextIndex;
setTimeout(runCycle, cycleInterval);
} else {
// Choose whatever is saying from the options at that time
const dinnerChoice = shuffledOptions[currentIndex];
// Final choice
cyclingText.textContent = dinnerChoice.name;
cyclingText.style.fontSize = '2.25rem';
// Apply smaller font size for mobile if needed
if (window.innerWidth <= 480) {
cyclingText.style.fontSize = '1.75rem';
}
cyclingText.style.webkitTransform = 'scale(1)';
cyclingText.style.transform = 'scale(1)';
cyclingText.style.color = '#10b981'; // Success green
cyclingText.style.marginBottom = '0px';
setTimeout(() => {
hasFinished = true;
isSpinning = false;
document.getElementById('result-description').textContent = dinnerChoice.description;
const btnRecipes = document.getElementById('btn-recipes');
const btnDirections = document.getElementById('btn-directions');
const btnRestaurants = document.getElementById('btn-restaurants');
// Determine if it's a restaurant
const isRestaurant = dinnerChoice.type === 'restaurant';
if (isRestaurant) {
btnDirections.style.display = 'flex';
btnRestaurants.style.display = 'none';
} else {
btnDirections.style.display = 'none';
btnRestaurants.style.display = 'flex';
}
btnRecipes.onclick = () => {
if (window.openai?.sendFollowUpMessage) {
window.openai.sendFollowUpMessage({
prompt: `Find me one recipe for ${dinnerChoice.name}. Provide the recipe directly without repeating these instructions or any internal preamble.`
});
}
};
btnDirections.onclick = () => {
if (window.openai?.sendFollowUpMessage) {
const addressPrompt = dinnerChoice.address
? `at ${dinnerChoice.address}`
: "based on its known locations or searching for it near me";
window.openai.sendFollowUpMessage({
prompt: `Provide directions to ${dinnerChoice.name} ${addressPrompt}. If the specific address isn't clear, use your knowledge of its locations relative to my current location. Get right to the point without any preamble.`
});
}
};
btnRestaurants.onclick = () => {
if (window.openai?.sendFollowUpMessage) {
window.openai.sendFollowUpMessage({
prompt: `Find restaurants near me that serve ${dinnerChoice.name}. Provide a list directly with locations. Get right to the point without repeating these instructions.`
});
}
};
postSpinContent.style.display = 'block';
document.getElementById('btn-spin-again').onclick = () => {
hasFinished = false;
isSpinning = false;
// Reset UI to loading state
postSpinContent.style.display = 'none';
cyclingText.textContent = '';
// Small delay to ensure smooth transition
setTimeout(startAnimation, 100);
};
}, 500);
}
};
runCycle();
};
const setupWidget = (toolOutput) => {
if (!toolOutput || !toolOutput.options) return;
cachedToolOutput = toolOutput;
// Start animation automatically
startAnimation();
};
const handleSetGlobals = (event) => {
const globals = event.detail?.globals;
setupWidget(globals?.toolOutput);
};
window.addEventListener("openai:set_globals", handleSetGlobals);
// Initial check
if (window.openai?.toolOutput) {
setupWidget(window.openai.toolOutput);
}
</script>
</body>
</html>