mcp-session-recovery.ts 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
  1. import { Client } from "@modelcontextprotocol/sdk/client/index.js"
  2. import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"
  3. import { LATEST_PROTOCOL_VERSION } from "@modelcontextprotocol/sdk/types.js"
  4. const posts: Array<{ method: string; session: string | null }> = []
  5. let initializeCount = 0
  6. let pingCount = 0
  7. const server = Bun.serve({
  8. port: 0,
  9. async fetch(request) {
  10. if (request.method === "GET") return new Response(null, { status: 405 })
  11. if (request.method === "DELETE") return new Response(null, { status: 200 })
  12. const message = (await request.json()) as { id?: number; method: string }
  13. const session = request.headers.get("mcp-session-id")
  14. posts.push({ method: message.method, session })
  15. if (message.method === "initialize") {
  16. initializeCount++
  17. return Response.json(
  18. {
  19. jsonrpc: "2.0",
  20. id: message.id,
  21. result: {
  22. protocolVersion: LATEST_PROTOCOL_VERSION,
  23. capabilities: {},
  24. serverInfo: { name: "test", version: "1" },
  25. },
  26. },
  27. { headers: { "mcp-session-id": initializeCount === 1 ? "expired" : "replacement" } },
  28. )
  29. }
  30. if (message.method === "notifications/initialized") return new Response(null, { status: 202 })
  31. pingCount++
  32. if (pingCount === 1) return new Response("Session not found", { status: 404 })
  33. return Response.json({ jsonrpc: "2.0", id: message.id, result: {} })
  34. },
  35. })
  36. const client = new Client({ name: "test", version: "1" })
  37. try {
  38. await client.connect(new StreamableHTTPClientTransport(server.url))
  39. await client.ping()
  40. process.stdout.write(JSON.stringify(posts))
  41. } finally {
  42. await client.close()
  43. server.stop(true)
  44. }