Skip to content

Add SSE support with auth and token storage#10

Merged
eyalzh merged 5 commits intomainfrom
add-sse-support
Aug 25, 2025
Merged

Add SSE support with auth and token storage#10
eyalzh merged 5 commits intomainfrom
add-sse-support

Conversation

@eyalzh
Copy link
Owner

@eyalzh eyalzh commented Aug 25, 2025

  • Add SSE transport support
  • Support auth flows
  • Add keychain based token storage
  • Add auth server for callback management in oauth flows

Note: This requires a yet to be released version of the python MCP SDK due to a timeout bug in the current version.

@eyalzh eyalzh requested a review from Copilot August 25, 2025 08:44

This comment was marked as outdated.

@eyalzh eyalzh requested a review from Copilot August 25, 2025 15:09
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds comprehensive SSE (Server-Sent Events) transport support for MCP clients with OAuth authentication and secure token storage. The implementation includes session management, keychain-based token storage with file fallback, and an integrated auth server for OAuth flows.

  • Add SSE transport support with OAuth client provider integration
  • Implement dual storage strategy for OAuth tokens (keychain + file fallback)
  • Add session manager for pre-initialized MCP client connections

Reviewed Changes

Copilot reviewed 22 out of 23 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pyproject.toml Adds new dependencies for SSE support (fastapi, uvicorn, keyring) and updates MCP version
state.py Integrates token storage management with project state
mcp_client/token_storage.py Implements keychain-based token storage with secure file fallback
mcp_client/session_manager.py Manages pre-initialized MCP client sessions for improved performance
auth_server/ FastAPI-based OAuth callback server for handling authorization flows
engine/ Refactors template engine with improved module organization
util/terminal.py Adds terminal utility functions for hyperlink support
tests/ Updates test templates and improves test isolation

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment on lines 185 to 190
# Write back to file with restricted permissions
with open(self.fallback_file, "w") as f:
json.dump(existing_data, f, indent=2)

# Set restrictive permissions (owner read/write only)
os.chmod(self.fallback_file, stat.S_IRUSR | stat.S_IWUSR)
Copy link

Copilot AI Aug 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a race condition where the file is created with default permissions before being restricted. The file should be created with restrictive permissions from the start using os.open() with mode parameter or setting umask.

Suggested change
# Write back to file with restricted permissions
with open(self.fallback_file, "w") as f:
json.dump(existing_data, f, indent=2)
# Set restrictive permissions (owner read/write only)
os.chmod(self.fallback_file, stat.S_IRUSR | stat.S_IWUSR)
# Write back to file with restricted permissions (owner read/write only)
flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
mode = stat.S_IRUSR | stat.S_IWUSR # 0o600
with os.fdopen(os.open(self.fallback_file, flags, mode), "w") as f:
json.dump(existing_data, f, indent=2)

Copilot uses AI. Check for mistakes.

This comment was marked as outdated.

@eyalzh eyalzh requested a review from Copilot August 25, 2025 16:04
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds SSE (Server-Sent Events) transport support to the MCP client, implements OAuth authentication flows, and introduces keychain-based token storage. The changes enable secure authentication with MCP servers and persistent token storage across sessions.

Key changes:

  • SSE transport support with OAuth authentication flows
  • Keychain-based token storage with file fallback for security
  • FastAPI-based auth server for handling OAuth callbacks

Reviewed Changes

Copilot reviewed 22 out of 23 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
pyproject.toml Added dependencies for FastAPI, keyring, uvicorn, and upgraded MCP version
mcp_client/token_storage.py New keychain storage implementation with file fallback
auth_server/auth_server.py FastAPI-based OAuth callback server
mcp_client/session_manager.py Session management for pre-initialized MCP connections
mcp_client/client_session_provider.py Updated to support SSE with OAuth and token storage
tests/e2e/test_e2e.py Updated test fixtures for better isolation

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment on lines +47 to +65
if self._callback_future and not self._callback_future.done():
# Schedule the exception in the main event loop
if self._main_loop:
self._main_loop.call_soon_threadsafe(
self._callback_future.set_exception,
Exception(f"OAuth error: {error} - {error_description}"),
)
return HTMLResponse(
content=f"<html><body><h2>Authentication Error</h2><p>{error}: {error_description}</p></body></html>", # noqa: E501
status_code=400,
)

if not code:
if self._callback_future and not self._callback_future.done():
# Schedule the exception in the main event loop
if self._main_loop:
self._main_loop.call_soon_threadsafe(
self._callback_future.set_exception, Exception("No authorization code received")
)
Copy link

Copilot AI Aug 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The callback error handling logic is duplicated in multiple places. Consider extracting this into a helper method like _set_callback_exception() to reduce code duplication.

Suggested change
if self._callback_future and not self._callback_future.done():
# Schedule the exception in the main event loop
if self._main_loop:
self._main_loop.call_soon_threadsafe(
self._callback_future.set_exception,
Exception(f"OAuth error: {error} - {error_description}"),
)
return HTMLResponse(
content=f"<html><body><h2>Authentication Error</h2><p>{error}: {error_description}</p></body></html>", # noqa: E501
status_code=400,
)
if not code:
if self._callback_future and not self._callback_future.done():
# Schedule the exception in the main event loop
if self._main_loop:
self._main_loop.call_soon_threadsafe(
self._callback_future.set_exception, Exception("No authorization code received")
)
self._set_callback_exception(Exception(f"OAuth error: {error} - {error_description}"))
return HTMLResponse(
content=f"<html><body><h2>Authentication Error</h2><p>{error}: {error_description}</p></body></html>", # noqa: E501
status_code=400,
)
if not code:
self._set_callback_exception(Exception("No authorization code received"))

Copilot uses AI. Check for mistakes.
@eyalzh eyalzh merged commit b9854d1 into main Aug 25, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant