route.ts
1 import { NextResponse } from 'next/server' 2 import { safeParseBody } from '@/lib/server/safe-parse-body' 3 import { loadMcpServers, saveMcpServers, deleteMcpServer } from '@/lib/server/storage' 4 import { mutateItem, deleteItem, notFound, type CollectionOps } from '@/lib/server/collection-helpers' 5 import { evictMcpClient } from '@/lib/server/mcp-connection-pool' 6 7 // eslint-disable-next-line @typescript-eslint/no-explicit-any 8 const ops: CollectionOps<any> = { load: loadMcpServers, save: saveMcpServers, deleteFn: deleteMcpServer } 9 10 export async function GET(_req: Request, { params }: { params: Promise<{ id: string }> }) { 11 const { id } = await params 12 const servers = loadMcpServers() 13 if (!servers[id]) return notFound() 14 return NextResponse.json(servers[id]) 15 } 16 17 export async function PUT(req: Request, { params }: { params: Promise<{ id: string }> }) { 18 const { id } = await params 19 const { data: body, error } = await safeParseBody(req) 20 if (error) return error 21 const result = mutateItem(ops, id, (server) => ({ 22 ...server, ...body, id, updatedAt: Date.now(), 23 })) 24 if (!result) return notFound() 25 // Connection pool caches by config fingerprint; evicting here is defense in 26 // depth — getOrConnectMcpClient also detects fingerprint mismatches. 27 await evictMcpClient(id) 28 return NextResponse.json(result) 29 } 30 31 export async function DELETE(_req: Request, { params }: { params: Promise<{ id: string }> }) { 32 const { id } = await params 33 if (!deleteItem(ops, id)) return notFound() 34 await evictMcpClient(id) 35 return NextResponse.json({ deleted: id }) 36 }