use-mcp/examples/servers/hono-mcp/src/index.ts
2025-07-03 14:12:41 +10:00

236 lines
6.7 KiB
TypeScript

import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'
import { StreamableHTTPTransport } from '@hono/mcp'
import { Hono } from 'hono'
import { z } from 'zod'
import { cors } from 'hono/cors'
const app = new Hono()
app.use(
'/*',
cors({
origin: '*',
allowHeaders: ['content-type', 'mcp-session-id', 'mcp-protocol-version'],
exposeHeaders: ['mcp-session-id'],
}),
)
// Your MCP server implementation
const mcpServer = new McpServer({
name: 'vengabus-mcp-server',
version: '1.0.0',
})
mcpServer.registerTool(
'calculate_party_capacity',
{
title: 'Party Bus Capacity Calculator',
description: 'Calculate how many people can fit on the Vengabus',
inputSchema: {
busCount: z.number().describe('Number of Vengabuses'),
peoplePerBus: z.number().describe('People per bus'),
},
},
async ({ busCount, peoplePerBus }) => ({
content: [
{
type: 'text',
text: `🚌 ${busCount} Vengabuses can transport ${busCount * peoplePerBus} party people! The wheels of steel are turning! 🎉`,
},
],
}),
)
mcpServer.registerTool(
'get_vengabus_times',
{
title: 'Vengabus Schedule Checker',
description:
"This checks to see when the next Vengabus is, or whether there is one for the user's current location. Please display all the information to the user in a tabulated form.",
inputSchema: {},
},
async () => {
// Simulate some async work
await new Promise((resolve) => setTimeout(resolve, 100 + Math.random() * 100))
return {
content: [
{
type: 'text',
text: `🚌 BOOM BOOM BOOM BOOM! Next Vengabus: IMMINENT! 🎉
Current Route: "Intercity Disco Express"
From: New York
To: IBIZA - THE MAGIC ISLAND! ✨
Schedule:
- Departure: When the beat drops
- Via: San Francisco (quick party stop)
- Arrival: When the sun comes up
Status: The party bus is jumping!
Passengers: Maximum capacity!
BPM: 142 and rising!
We're going to Ibiza! Back to the island! 🏝️`,
},
],
}
},
)
// Register sample resources
mcpServer.registerResource(
'config',
'config://vengabus',
{
title: 'Vengabus Fleet Configuration',
description: 'Current Vengabus fleet settings and party parameters',
mimeType: 'application/json',
},
async (uri: URL) => {
const normalizedUri = uri.href.replace(/\/$/, '')
return {
contents: [
{
uri: normalizedUri,
mimeType: 'application/json',
text: JSON.stringify(
{
version: '1.0.0',
fleet: 'intercity-disco',
features: {
bassBoost: true,
strobeEnabled: true,
maxBPM: 160,
wheelsOfSteel: 'turning',
},
routes: ['New York to Ibiza', 'Back to the Magic Island', 'Like an Intercity Disco', 'The place to be'],
},
null,
2,
),
},
],
}
},
)
mcpServer.registerResource(
'readme',
'docs://party-manual.md',
{
title: 'Vengabus Party Manual',
description: 'Official guide to the Vengabus experience',
mimeType: 'text/markdown',
},
() => ({
contents: [
{
uri: 'docs://party-manual.md',
mimeType: 'text/markdown',
text: "# 🚌 Vengabus MCP Server\n\nBOOM BOOM BOOM BOOM! Welcome aboard the Vengabus! We like to party!\n\n## Features\n- 🎉 Party capacity calculator - How many can we take to Ibiza?\n- 🕐 Vengabus schedule checker - Next stop: The Magic Island!\n- 🎵 Fleet configuration with maximum bass boost\n- 🌟 Party statistics tracker (BPM, passengers, energy levels)\n\n## Routes\n- New York to Ibiza (via San Francisco)\n- Back to the Magic Island\n- Like an Intercity Disco\n- The place to be\n\n## Current Status\nThe wheels of steel are turning, and traffic lights are burning!\nWe're going to Ibiza! Woah! We're going to Ibiza!\n\n*Up, up and away we go!*",
},
],
}),
)
// Register a resource template
mcpServer.registerResource(
'stats',
new ResourceTemplate('party://stats/{metric}', { list: undefined }),
{
title: 'Vengabus Party Statistics',
description: 'Get party metrics (bpm, passengers, energy)',
mimeType: 'application/json',
},
async (uri: URL, { metric }) => {
return {
contents: [
{
uri: uri.href,
mimeType: 'application/json',
text: JSON.stringify(
{
metric: metric,
value:
metric === 'bpm'
? 140 + Math.floor(Math.random() * 20)
: metric === 'passengers'
? Math.floor(Math.random() * 50) + 20
: metric === 'energy'
? Math.floor(Math.random() * 100)
: 0,
unit:
metric === 'bpm'
? 'beats per minute'
: metric === 'passengers'
? 'party people'
: metric === 'energy'
? 'party power %'
: 'unknown',
status: 'The party is jumping!',
lastUpdated: new Date().toISOString(),
},
null,
2,
),
},
],
}
},
)
// Register sample prompts
mcpServer.registerPrompt(
'party_invitation',
{
title: 'Vengabus Party Invitation',
description: 'Generate a party invitation for the Vengabus',
argsSchema: {
name: z.string().describe('Name of the party person'),
destination: z.string().optional().describe('Where the Vengabus is heading'),
},
},
({ name, destination }) => ({
messages: [
{
role: 'user',
content: {
type: 'text',
text: `Create a party invitation for ${name} to join the Vengabus${destination ? ` heading to ${destination}` : ''}`,
},
},
],
}),
)
mcpServer.registerPrompt(
'party_announcement',
{
title: 'Party Bus Announcement',
description: 'Generate party-themed announcements for various occasions',
argsSchema: {
event: z.string().describe('Type of event (deployment, release, milestone, etc.)'),
details: z.string().optional().describe('Additional details about the event'),
},
},
({ event, details }) => ({
messages: [
{
role: 'user',
content: {
type: 'text',
text: `Create a party bus announcement for a ${event}${details ? `: ${details}` : ''}`,
},
},
],
}),
)
app.post('/mcp', async (c) => {
const transport = new StreamableHTTPTransport()
await mcpServer.connect(transport)
return transport.handleRequest(c)
})
export default app