release: 0.1.6 — relay notifications/progress to MCP client
All checks were successful
build / test (push) Successful in 30s
publish / npm (push) Successful in 33s

Long-running upstream skills emit MCP notifications/progress on the SSE
stream. Without forwarding, the gateway swallows them and the MCP
client (Claude Code, Cursor) aborts the tools/call on its idle timer
after ~60s — even though the HTTP stream stays warm.

Gateway now passes the SDK's extra.sendNotification through to
UpstreamAgent.callTool. Any non-response frame with a method but no id
becomes a notification on the client side. Each tools/call carries a
progressToken (client-supplied or request-id fallback) so the client
can correlate.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-15 21:37:58 -03:00
parent 09b588326c
commit 45e12324df
4 changed files with 52 additions and 7 deletions

View File

@@ -95,7 +95,7 @@ export async function buildGateway(opts: GatewayOptions = {}): Promise<GatewayHa
return { tools };
});
server.setRequestHandler(CallToolRequestSchema, async (req) => {
server.setRequestHandler(CallToolRequestSchema, async (req, extra) => {
const fullName = req.params.name;
const idx = fullName.indexOf(SEP);
if (idx < 0) {
@@ -107,10 +107,30 @@ export async function buildGateway(opts: GatewayOptions = {}): Promise<GatewayHa
if (!upstream) {
return _softError(`unknown agent: ${agentName}`) as any;
}
// Honor the client's progressToken if it supplied one; else fall
// back to the request id. Either way, when upstream emits
// notifications/progress we forward them via the SDK's
// sendNotification so clients like Claude Code reset their idle
// tool-call timer and don't abort long builds.
const clientToken = (req.params._meta as any)?.progressToken as
| string
| number
| undefined;
const progressToken = clientToken ?? (extra.requestId as string | number);
try {
const result = await upstream.callTool(
toolName,
(req.params.arguments as Record<string, unknown>) ?? {},
{
progressToken,
onNotification: async (notif) => {
try {
await extra.sendNotification(notif as any);
} catch {
// best effort
}
},
},
);
// Pass through the upstream's CallToolResult as-is. Upstreams already
// populate content / structuredContent / isError per the MCP spec.