Skip to content

Commit 8f05103

Browse files
committed
feat: add stdio mode support for Sevalla MCP server
1 parent e46f4c3 commit 8f05103

File tree

1 file changed

+42
-27
lines changed

1 file changed

+42
-27
lines changed

src/index.ts

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
import { serve } from '@hono/node-server'
22
import { StreamableHTTPTransport } from '@hono/mcp'
33
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
4+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
45
import { createTools } from './sandbox/index.ts'
56
import { Hono } from 'hono'
67
import { HTTPException } from 'hono/http-exception'
78
import { cors } from 'hono/cors'
89
import { createOAuthRouter } from './oauth.ts'
910
import { INDEX_HTML } from './html.ts'
1011

12+
const IS_STDIO = process.argv.includes('--stdio')
13+
if (IS_STDIO) {
14+
console.log = console.error
15+
}
16+
1117
const PORT = parseInt(process.env.PORT || '3000', 10)
1218
const SEVALLA_API_BASE = 'https://api.sevalla.com'
1319
const SEVALLA_SPEC_URL = 'https://api.sevalla.com/v3/openapi.json'
@@ -153,34 +159,43 @@ app.post('/mcp', async (c) => {
153159
}
154160
})
155161

156-
await loadSpec()
157-
console.log(`Sevalla MCP server starting on port ${PORT}`)
158-
159-
const server = serve({
160-
fetch: app.fetch,
161-
port: PORT,
162-
})
162+
if (IS_STDIO) {
163+
const spec = await loadSpec()
164+
const token = process.env.SEVALLA_API_KEY || ''
165+
const mcpServer = createMcpServer(spec, token)
166+
const transport = new StdioServerTransport()
167+
await mcpServer.connect(transport)
168+
console.log('Sevalla MCP server running in stdio mode')
169+
} else {
170+
await loadSpec()
171+
console.log(`Sevalla MCP server starting on port ${PORT}`)
172+
173+
const server = serve({
174+
fetch: app.fetch,
175+
port: PORT,
176+
})
163177

164-
const shutdown = (signal: string) => {
165-
if (isShuttingDown) {
166-
return
178+
const shutdown = (signal: string) => {
179+
if (isShuttingDown) {
180+
return
181+
}
182+
isShuttingDown = true
183+
console.log(`${signal} received, starting graceful shutdown...`)
184+
185+
const forceExit = setTimeout(() => {
186+
console.error('Graceful shutdown timed out, forcing exit')
187+
process.exit(1)
188+
}, SHUTDOWN_TIMEOUT_MS)
189+
forceExit.unref()
190+
191+
server.close(() => {
192+
console.log('All connections closed, exiting')
193+
process.exit(0)
194+
})
167195
}
168-
isShuttingDown = true
169-
console.log(`${signal} received, starting graceful shutdown...`)
170-
171-
const forceExit = setTimeout(() => {
172-
console.error('Graceful shutdown timed out, forcing exit')
173-
process.exit(1)
174-
}, SHUTDOWN_TIMEOUT_MS)
175-
forceExit.unref()
176-
177-
server.close(() => {
178-
console.log('All connections closed, exiting')
179-
process.exit(0)
180-
})
181-
}
182196

183-
process.on('SIGTERM', () => shutdown('SIGTERM'))
184-
process.on('SIGINT', () => shutdown('SIGINT'))
197+
process.on('SIGTERM', () => shutdown('SIGTERM'))
198+
process.on('SIGINT', () => shutdown('SIGINT'))
185199

186-
console.log(`Sevalla MCP server listening on http://localhost:${PORT}`)
200+
console.log(`Sevalla MCP server listening on http://localhost:${PORT}`)
201+
}

0 commit comments

Comments
 (0)