History

lint: use typed-error idioms in fallback error handling

Rhys Sullivan committed 4 months ago

Commit 1a8357b1 parent afa2c9a2 files · +16 −15Browse files

Unified · Split

2 files
  1. packages/plugins/mcp/src/sdk/connection.ts +10 −8
  2. packages/plugins/mcp/src/sdk/plugin.test.ts +6 −7
packages/plugins/mcp/src/sdk/connection.ts+10−8
@@ -351,9 +351,11 @@ export const createMcpConnector = (input: ConnectorInput): McpConnector => { · 350 unmodified lines
351 // error), which used to misclassify an expired token as a generic351 // error), which used to misclassify an expired token as a generic
352 // connection failure. Propagate it as-is instead.352 // connection failure. Propagate it as-is instead.
353 return connectStreamableHttp.pipe(353 return connectStreamableHttp.pipe(
354 Effect.catch((error) => {354 Effect.catch((failure) => {
355 if (Predicate.isTagged(error, "McpOAuthReauthorizationRequired")) return Effect.fail(error);355 if (Predicate.isTagged(failure, "McpOAuthReauthorizationRequired")) {
356 if (error.httpStatus === 401 || error.httpStatus === 403) return Effect.fail(error);356 return Effect.fail(failure);
357 }
358 if (failure.httpStatus === 401 || failure.httpStatus === 403) return Effect.fail(failure);
357 // When the fallback ALSO fails, the streamable-http failure is the359 // When the fallback ALSO fails, the streamable-http failure is the
358 // interesting one: most modern servers don't serve legacy SSE at all360 // interesting one: most modern servers don't serve legacy SSE at all
359 // (GET → 405), so reporting only "Failed connecting via sse" points361 // (GET → 405), so reporting only "Failed connecting via sse" points
@@ -362,16 +364,16 @@ export const createMcpConnector = (input: ConnectorInput): McpConnector => { · 2 unmodified lines
362 return connectSse.pipe(364 return connectSse.pipe(
363 Effect.catch(365 Effect.catch(
364 (366 (
365 sseError,367 sseFailure,
366 ): Effect.Effect<never, McpConnectionError | McpOAuthReauthorizationRequired> => {368 ): Effect.Effect<never, McpConnectionError | McpOAuthReauthorizationRequired> => {
367 if (Predicate.isTagged(sseError, "McpOAuthReauthorizationRequired")) {369 if (Predicate.isTagged(sseFailure, "McpOAuthReauthorizationRequired")) {
368 return Effect.fail(sseError);370 return Effect.fail(sseFailure);
369 }371 }
370 return Effect.fail(372 return Effect.fail(
371 new McpConnectionError({373 new McpConnectionError({
372 transport: "streamable-http",374 transport: "streamable-http",
373 message: `${error.message}; SSE fallback also failed: ${sseError.message}`,375 message: `${failure.message}; SSE fallback also failed: ${sseFailure.message}`,
374 ...(error.httpStatus === undefined ? {} : { httpStatus: error.httpStatus }),376 ...(failure.httpStatus === undefined ? {} : { httpStatus: failure.httpStatus }),
375 }),377 }),
376 );378 );
377 },379 },
packages/plugins/mcp/src/sdk/plugin.test.ts+6−7
@@ -408,18 +408,17 @@ describe("mcpPlugin", () => { · 407 unmodified lines
408 ),408 ),
409 );409 );
410 410
411 const error = yield* createMcpConnector({411 const failure = yield* createMcpConnector({
412 transport: "remote",412 transport: "remote",
413 endpoint: "https://internal.example/mcp",413 endpoint: "https://internal.example/mcp",
414 httpClientLayer,414 httpClientLayer,
415 }).pipe(Effect.flip);415 }).pipe(Effect.flip);
416 416
417 if (!Predicate.isTagged(error, "McpConnectionError")) {417 expect(Predicate.isTagged(failure, "McpConnectionError")).toBe(true);
418 throw new TypeError(`expected McpConnectionError, got ${error._tag}`);418 if (!Predicate.isTagged(failure, "McpConnectionError")) return;
419 }419 expect(failure.message).toContain("streamable-http");
420 expect(error.message).toContain("streamable-http");420 expect(failure.message).toContain("SSE fallback also failed");
421 expect(error.message).toContain("SSE fallback also failed");421 expect(failure.httpStatus).toBe(500);
422 expect(error.httpStatus).toBe(500);
423 }),422 }),
424 );423 );
425 424