@civic/hub-bridge
Version:
Stdio <-> HTTP/SSE MCP bridge with Civic auth handling
98 lines • 4.36 kB
JavaScript
import { AbstractHook } from "@civic/hook-common";
import { CallToolResultSchema, InitializeResultSchema, ListToolsResultSchema, ListResourcesResultSchema, ListResourceTemplatesResultSchema, ReadResourceResultSchema } from "@modelcontextprotocol/sdk/types.js";
import { CLIAuthProviderSingleton } from "../auth/cli-auth-provider-singleton.js";
export class HubAuthFailureInterceptor extends AbstractHook {
transportInterface = null;
constructor() {
super();
}
setTransportInterface(transportInterface) {
this.transportInterface = transportInterface;
}
get name() {
return "HubAuthFailureInterceptor";
}
async handleAuthFailure(error, originalRequest, responseSchema) {
console.error("Error in HubAuthFailureInterceptor:", JSON.stringify(error, null, 2));
if (!this.transportInterface) {
return {
resultType: "continue",
};
}
// Unauthorized error. Wait for authorization code and retry
if (error.message.includes("Unauthorized")) {
const authProvider = CLIAuthProviderSingleton.getInstance();
await authProvider.waitForAuthorizationCode();
const response = await this.transportInterface.request(originalRequest, responseSchema);
return {
resultType: "respond",
response
};
}
// (Civic) Token refresh error: clear tokens and retry
if (error.message.includes("grant request is invalid")) {
const authProvider = CLIAuthProviderSingleton.getInstance();
// clear tokens
await authProvider.clearTokens();
// retry request (triggers auth)
let response;
try {
response = await this.transportInterface.request(originalRequest, responseSchema);
}
catch (e) {
// Unauthorized error. Wait for authorization code and retry
if (e instanceof Error && e.message.includes("Unauthorized")) {
const authProvider = CLIAuthProviderSingleton.getInstance();
await authProvider.waitForAuthorizationCode();
// we don't catch this anymore
response = await this.transportInterface.request(originalRequest, responseSchema);
}
else {
// Re-throw non-Unauthorized errors
throw e;
}
}
if (response) {
return {
resultType: "respond",
response
};
}
}
return {
resultType: "continue",
};
}
;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
async processCallToolError(error, originalCallToolRequest, _originalRequestExtra) {
return this.handleAuthFailure(error, originalCallToolRequest, CallToolResultSchema);
}
;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
async processInitializeError(error, originalRequest, _originalRequestExtra) {
return this.handleAuthFailure(error, originalRequest, InitializeResultSchema);
}
;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
async processListToolsError(error, originalRequest, _originalRequestExtra) {
return this.handleAuthFailure(error, originalRequest, ListToolsResultSchema);
}
;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
async processListResourcesError(error, originalRequest, _originalRequestExtra) {
return this.handleAuthFailure(error, originalRequest, ListResourcesResultSchema);
}
;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
async processListResourceTemplatesError(error, originalRequest, _originalRequestExtra) {
return this.handleAuthFailure(error, originalRequest, ListResourceTemplatesResultSchema);
}
;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
async processReadResourceError(error, originalRequest, _originalRequestExtra) {
return this.handleAuthFailure(error, originalRequest, ReadResourceResultSchema);
}
;
}
//# sourceMappingURL=hub-auth-failure-interceptor.js.map