Skip to content

Commit 4c565ad

Browse files
committed
feat: add manual oauth callback endpoint for better remote mcp-hub cases
1 parent f0eb7ce commit 4c565ad

File tree

2 files changed

+53
-1
lines changed

2 files changed

+53
-1
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [3.5.0] - 2025-06-24
9+
10+
### Added
11+
12+
- Manual OAuth callback endpoint for improved headless server support
13+
- Support for manual authorization flow in remote/headless environments
14+
815
## [3.4.5] - 2025-06-18
916

1017
### Fixed
@@ -470,3 +477,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
470477
- API documentation
471478
- Example implementations
472479
- Test suite with high coverage
480+

src/server.js

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -658,7 +658,52 @@ registerRoute(
658658
}
659659
)
660660

661+
//For cases where mcp-hub is running on a remote system and the oauth callback points to localhost
662+
registerRoute(
663+
"POST",
664+
"/oauth/manual_callback",
665+
"Handle OAuth callback for manual authorization",
666+
async (req, res) => {
667+
let code, server_name
668+
try {
661669

670+
const {url} = req.body || {}
671+
if (!url) {
672+
throw new ValidationError("Missing URL parameter", { field: "url" });
673+
}
674+
const url_with_code = new URL(url)
675+
if (url_with_code.searchParams.has('code')) {
676+
code = url_with_code.searchParams.get('code')
677+
}
678+
if (url_with_code.searchParams.has('server_name')) {
679+
server_name = url_with_code.searchParams.get('server_name')
680+
}
681+
if (!code || !server_name) {
682+
throw new ValidationError("Missing code or server_name parameter");
683+
}
684+
//simulate delay
685+
// await new Promise(resolve => setTimeout(resolve, 3000));
686+
const connection = serviceManager.mcpHub.getConnection(server_name);
687+
await connection.handleAuthCallback(code)
688+
// // Still broadcast the update for consistency
689+
serviceManager.broadcastSubscriptionEvent(SubscriptionTypes.SERVERS_UPDATED, {
690+
changes: {
691+
modified: [server_name],
692+
}
693+
});
694+
return res.json({
695+
status: "ok",
696+
message: `Authorization successful for server '${server_name}'`,
697+
server_name,
698+
timestamp: new Date().toISOString(),
699+
});
700+
} catch (error) {
701+
throw wrapError(error, "MANUAL_OAUTH_CALLBACK_ERROR", {
702+
url: req.body?.url || null,
703+
});
704+
}
705+
}
706+
)
662707
registerRoute(
663708
"GET",
664709
"/oauth/callback",
@@ -719,7 +764,6 @@ registerRoute(
719764

720765
const connection = serviceManager.mcpHub.getConnection(server_name);
721766

722-
// Process authentication asynchronously
723767
await connection.handleAuthCallback(code)
724768
res.write('<script>updateStatus("success");</script>');
725769

0 commit comments

Comments
 (0)