Skip to main content
Glama

MCP Doc Server

app.ts5.29 kB
import express from 'express' import type { Request, Response, NextFunction } from 'express' import { join } from 'path' import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js' import { getSiteMap, getDocContentByUri, handleMdxContent, } from './utils/mdx.js' import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js' import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js' import { randomUUID } from 'node:crypto' import cors from 'cors' const DOCS_DIST_DIR = join(process.cwd(), '.docs') export const createApp = (server: McpServer) => { const app = express() app.use(cors()) app.use(express.json()) // Map to store transports by session ID const transports: { [sessionId: string]: StreamableHTTPServerTransport } = {} app.get('/', (_req: Request, res: Response) => { res.send('Hello, this is the MCP server!') }) app.get('/health', (_req: Request, res: Response) => { res.json({ status: 'ok', message: 'MCP server is running', time: new Date().toISOString(), }) }) app.get('/sitemap', async (_req: Request, res: Response) => { const siteMapFile = join(DOCS_DIST_DIR, 'sitemap.xml') const siteMapContent = await getSiteMap(siteMapFile) console.log('siteMapContent', siteMapContent) const siteMap = siteMapContent.map((item) => ({ uri: `docs://${item.loc}`, text: `Documentation: ${item.loc}`, })) res.json({ contents: siteMap, siteMapFile, }) }) // Handle POST requests for client-to-server communication app.post('/mcp', async (req: Request, res: Response) => { // Check for existing session ID const sessionId = req.headers['mcp-session-id'] as string | undefined let transport: StreamableHTTPServerTransport if (sessionId && transports[sessionId]) { // Reuse existing transport transport = transports[sessionId] } else if (!sessionId && isInitializeRequest(req.body)) { // New initialization request transport = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID(), onsessioninitialized: (sessionId) => { // Store the transport by session ID transports[sessionId] = transport }, }) // Clean up transport when closed transport.onclose = () => { if (transport.sessionId) { delete transports[transport.sessionId] } } // const server = new McpServer({ // name: 'example-server', // version: '1.0.0', // }) // ... set up server resources, tools, and prompts ... // Connect to the MCP server await server.connect(transport) } else { // Invalid request res.status(400).json({ jsonrpc: '2.0', error: { code: -32000, message: 'Bad Request: No valid session ID provided', }, id: null, }) return } // Handle the request await transport.handleRequest(req, res, req.body) }) // Reusable handler for GET and DELETE requests const handleSessionRequest = async ( req: express.Request, res: express.Response ) => { const sessionId = req.headers['mcp-session-id'] as string | undefined if (!sessionId || !transports[sessionId]) { res.status(400).send('Invalid or missing session ID') return } const transport = transports[sessionId] await transport.handleRequest(req, res) } // Handle GET requests for server-to-client notifications via SSE app.get('/mcp', handleSessionRequest) // Handle DELETE requests for session termination app.delete('/mcp', handleSessionRequest) // 添加获取文档内容接口 - 使用中间件方式 const docContentMiddleware = async ( _req: Request, res: Response, next: NextFunction ) => { const uri = _req.query.uri as string const isPretty = _req.query.isPretty as string if (!uri) { return res.status(400).json({ error: 'URI参数必须提供' }) } try { const rawContent = await getDocContentByUri(uri) const { content, metadata: { frontmatter }, } = handleMdxContent(rawContent) // res.json({ // uri: uri, // text: content, // }) console.log('uri', uri, isPretty) if (isPretty) { const escapedContent = content .replace(/</g, '&lt;') .replace(/>/g, '&gt;') const html = ` <!doctype html> <html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script> </head> <body> <pre style="word-wrap: break-word; white-space: pre-wrap;">${escapedContent}</pre> </body> </html> ` return res.send(html) } res.send(content) } catch (error) { console.error(`获取文档内容出错。URI: ${uri}`, error) res.status(500).json({ error: '获取文档内容失败' }) } } // @ts-ignore Express 5类型定义问题 app.use('/doc-content-by-uri', docContentMiddleware) return app }

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/Shengwang-Community/doc-mcp-server'

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