fix(mcp): return deprecation notice as isError tool result

isError: true is the one MCP mechanism Claude.ai cannot ignore —
it is obligated to surface tool errors to the user.

On the first tool call of a static-token session, return only the
deprecation notice with isError: true (no data). The per-session
_noticeEmitted flag is set before returning, so the immediate retry
(or any subsequent call) goes through normally and returns real data.
This commit is contained in:
jubnl
2026-04-10 03:03:37 +02:00
parent ce36b550c3
commit 89a109560e
+3 -4
View File
@@ -130,10 +130,9 @@ export function registerTripTools(server: McpServer, userId: number, scopes: str
}, },
async ({ include_archived }) => { async ({ include_archived }) => {
const notice = getDeprecationNotice(); const notice = getDeprecationNotice();
if (notice) return { isError: true as const, content: [{ type: 'text' as const, text: notice }] };
const trips = listTrips(userId, include_archived ? null : 0); const trips = listTrips(userId, include_archived ? null : 0);
// Embed notice as a top-level JSON field so Claude processes it as data, return ok({ trips });
// not as a separate content annotation it can silently ignore.
return ok({ ...(notice ? { _deprecation_notice: notice } : {}), trips });
} }
); );
@@ -171,8 +170,8 @@ export function registerTripTools(server: McpServer, userId: number, scopes: str
messageCount = countMessages(tripId); messageCount = countMessages(tripId);
} }
const notice = getDeprecationNotice(); const notice = getDeprecationNotice();
if (notice) return { isError: true as const, content: [{ type: 'text' as const, text: notice }] };
return ok({ return ok({
...(notice ? { _deprecation_notice: notice } : {}),
...summary, ...summary,
reservations: canReadRes ? summary.reservations : undefined, reservations: canReadRes ? summary.reservations : undefined,
packing: canReadPacking ? summary.packing : undefined, packing: canReadPacking ? summary.packing : undefined,