Skip to content

feat(mcp): add SSE server for remote MCP deployment#71

Merged
guzus merged 28 commits intomainfrom
feat/deploy-mcp-sse-server
Feb 9, 2026
Merged

feat(mcp): add SSE server for remote MCP deployment#71
guzus merged 28 commits intomainfrom
feat/deploy-mcp-sse-server

Conversation

@bullish-lee
Copy link
Collaborator

@bullish-lee bullish-lee commented Jan 24, 2026

Summary

  • Add SSE-based MCP server for remote deployment (Railway)
  • Add Dockerfile for containerized deployment
  • Add security utilities for credential handling via HTTP headers
  • Modify exchange manager to support per-request credentials

Closes #50

Test plan

@claude

Generated with Claude Code

@claude

This comment was marked as outdated.

@claude

This comment was marked as outdated.

@claude

This comment was marked as outdated.

@claude

This comment was marked as outdated.

@claude

This comment was marked as outdated.

@claude

This comment was marked as outdated.

@claude

This comment was marked as outdated.

@claude

This comment was marked as outdated.

@claude

This comment was marked as outdated.

bullish-lee and others added 9 commits January 25, 2026 13:59
- Add server_sse.py with Starlette/SSE transport for remote access
- Add Dockerfile for Railway deployment (Python 3.13-slim + uv)
- Add security.py for credential handling via HTTP headers
- Update exchange_manager.py with context-based credential injection
- Support all exchanges: Polymarket, Limitless, Opinion, Kalshi, Predict.fun

Endpoints:
- /health - Health check
- /sse - MCP SSE connection
- /messages/ - MCP message handling

Deployed at: https://dr-manhattan-mcp-production.up.railway.app

Closes #50

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously, claude-default would run on all pull_request_target events,
causing OIDC token failures for PRs without @claude mention.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Security:
- Replace CORS wildcard with configurable allowed origins
- Fully mask credentials in logs (no partial exposure)
- Fix Docker healthcheck (curl not available in slim image)
- Remove HTTP-specific error messages from exchange_manager

Code quality:
- Extract shared tool definitions to avoid 348-line duplication
- Add environment variable validation (PORT, LOG_LEVEL)
- Optimize Dockerfile layer caching
- Add comprehensive tests for SSE server

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Make TOOL_DISPATCH lazy to avoid mcp import in non-mcp tests
- Fix test file import ordering for ruff
- Skip MCP-dependent tests when mcp package not installed

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The conditional `import mcp` inside try/except block
confuses isort. Using skip_file directive is the standard
solution for test files with conditional imports.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@guzus guzus force-pushed the feat/deploy-mcp-sse-server branch from 3813883 to 48f8d21 Compare January 25, 2026 05:00
@claude
Copy link

claude bot commented Jan 25, 2026

PR Review: SSE-based MCP Server for Remote Deployment

I've reviewed PR #71 and overall this is a well-structured implementation that adds SSE transport for remote MCP deployment. Here's my detailed feedback:


✅ Strengths

Code Quality

  • Excellent separation of concerns: The tools/definitions.py module consolidates tool definitions, avoiding duplication between stdio and SSE transports
  • Proper logging architecture: Logger patching strategy correctly prevents stdout contamination in MCP protocol
  • Thread-safe credential handling: Context variables and locks properly protect concurrent access
  • Good documentation: Inline comments explain security rationale and architectural decisions

Security

  • Defense in depth approach:
    • Full credential masking in logs (no partial exposure) at dr_manhattan/mcp/utils/security.py:88
    • Credential zeroization on cleanup at dr_manhattan/mcp/session/exchange_manager.py:161-179
    • Transport-agnostic credential validation at dr_manhattan/mcp/utils/security.py:150-181
  • CORS properly configured: Restricted to known origins with sensible defaults at dr_manhattan/mcp/server_sse.py:268-275
  • Sensitive header detection: Comprehensive list covering all supported exchanges

Testing

  • Good test coverage: 342 lines of tests covering:
    • Credential extraction and validation
    • Header masking and sanitization
    • Environment validation
    • Health checks and endpoints
    • Tool definition consistency
  • Tests are well-organized: Clear class structure and descriptive test names
  • Graceful degradation: Tests skip when MCP package not installed

Deployment

  • Docker best practices:
    • Multi-stage layer optimization
    • UV for fast dependency management (follows CLAUDE.md rule Adds Polymarket data fetching capabilities #3)
    • Proper .dockerignore to exclude secrets and dev files
    • Health check using Python (no curl dependency)

⚠️ Issues & Recommendations

1. SECURITY CRITICAL: Credentials in Memory

Location: dr_manhattan/mcp/session/exchange_manager.py:136-144

The MCP_CREDENTIALS global dict stores private keys in memory for the application lifetime. While there's a _zeroize_credentials() function, this leaves credentials exposed to:

  • Memory dumps
  • Process inspection
  • Long-running process vulnerabilities

Recommendation:

  • Document this security trade-off prominently in README/docs
  • Consider adding option to use ephemeral credentials or secret management service (AWS Secrets Manager, HashiCorp Vault)
  • Add warning to users about using dedicated wallets with limited funds

2. CORS Security Gap

Location: dr_manhattan/mcp/server_sse.py:268-275

The default CORS configuration allows https://claude.ai and https://console.anthropic.com, but the comment says "MCP clients typically don't send Origin headers". This means:

  • Actual MCP clients will likely send requests with no Origin header
  • These will be rejected by the CORS middleware
  • The allowed origins list may not actually help

Recommendation:

  • Test with actual Claude Desktop/Code to verify Origin header behavior
  • If no Origin is sent, document that CORS provides limited protection
  • Consider adding request signing or API keys for production deployments

3. Missing Error Context in SSE Handler

Location: dr_manhattan/mcp/server_sse.py:188-207

The handle_sse() function doesn't catch exceptions from the SSE transport layer. If an error occurs, the credentials won't be logged (good!), but there's no error handling.

Recommendation:

try:
    async with sse_transport.connect_sse(...) as streams:
        await mcp_app.run(...)
except Exception as e:
    logger.error(f"SSE connection error: {sanitize_error_message(str(e))}")
    raise
finally:
    _request_credentials.reset(token)

4. Potential Race Condition in Credential Refresh

Location: dr_manhattan/mcp/session/exchange_manager.py:386-425

The refresh_credentials() method stops clients, deletes exchanges, then reloads credentials. Between deletion and reload, another thread could call get_exchange() and create an instance with stale credentials.

Fix: Move reload_credentials() before the deletion loop (already done at line 422, but could be clearer)

5. Health Check Hardcoded Port

Location: Dockerfile:29-30

The health check uses localhost:8080 but the PORT env var could be different at runtime.

Fix:

HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
    CMD python -c "import os; import urllib.request; urllib.request.urlopen(f'http://localhost:{os.getenv(\"PORT\", \"8080\")}/health')" || exit 1

6. Test Coverage Gaps

Missing tests:

  • SSE connection flow with actual MCP protocol messages
  • Credential refresh during active connections
  • Concurrent request handling with different credentials
  • Error scenarios in handle_sse() and handle_messages()
  • Timeout handling in _run_with_timeout()

Recommendation: Add integration tests for critical paths

7. Code Duplication: Logger Patching

Locations:

  • dr_manhattan/mcp/server.py:41-53
  • dr_manhattan/mcp/server_sse.py:35-46

The _mcp_setup_logger() function is identical in both files.

Recommendation: Extract to dr_manhattan/mcp/utils/logger.py and import in both servers

8. Incomplete Credential Validation

Location: dr_manhattan/mcp/utils/security.py:150-181

The validation only checks for presence of credentials, not their format (e.g., valid hex for private keys, valid address for funder).

Recommendation: Add format validation to fail fast with helpful error messages


🔍 Minor Issues

  1. Type hints inconsistency: Some functions use Dict, others use dict (Python 3.9+ allows lowercase). Standardize to one style.

  2. Unused import at server_sse.py:21: contextvars imported but used in the file

  3. Magic number at exchange_manager.py:373: ExchangeClient(exchange, 2.0, False) - the 2.0 timeout should be a named constant

  4. Comment at server_sse.py:232: Version "0.0.2" should be pulled from package metadata, not hardcoded


📊 Test Coverage Summary

Total test count: 23 tests across 5 test classes
Coverage: Good for security utilities, limited for SSE server itself

Covered:

  • ✅ Credential extraction (6 tests)
  • ✅ Credential masking (3 tests)
  • ✅ Credential validation (5 tests)
  • ✅ Health check (1 test)
  • ✅ Environment validation (3 tests)
  • ✅ Tool definitions (3 tests)

Not covered:

  • ❌ SSE connection lifecycle
  • ❌ Concurrent credential handling
  • ❌ Error scenarios in handlers
  • ❌ Credential refresh edge cases

🎯 Adherence to CLAUDE.md

Rule 1 (Focused, clean, understandable): Code is well-structured
Rule 2 (No unnecessary docs): No extra markdown files created
Rule 3 (Use UV): Dockerfile uses UV at line 8-9, 15
Rule 4 (Single source of truth): Defaults in code at exchange_manager.py:46-53
⚠️ Rule 5 (Run and debug): No evidence of manual testing beyond Railway deployment verification


📝 Recommendations Priority

High Priority (fix before merge):

  1. Document credential-in-memory security implications
  2. Fix health check port hardcoding
  3. Add exception handling to SSE handlers

Medium Priority:
4. Extract duplicated logger patching code
5. Add format validation for credentials
6. Add integration tests for SSE flow

Low Priority:
7. Standardize type hints
8. Extract magic numbers to constants
9. Pull version from package metadata


Summary

This is a solid implementation that demonstrates good security awareness and proper architectural patterns. The main concerns are around operational security (credentials in memory) and test coverage for the SSE transport layer. With the high-priority issues addressed, this PR is ready for merge.

Recommendation: ✅ Approve with minor changes

- Create wiki/mcp/remote-server.md with full setup guide
- Document credential headers for all exchanges
- Add multi-exchange configuration example
- Update README.md with remote server quick start
- Update wiki index

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@claude
Copy link

claude bot commented Jan 25, 2026

PR Review: SSE-based MCP Server for Remote Deployment

Overall Assessment

This is a well-structured PR that adds SSE (Server-Sent Events) transport for remote MCP deployment. The implementation is thoughtful with good security practices and comprehensive test coverage. However, there are several security concerns and potential issues that should be addressed.

Security Concerns

🔴 Critical

  1. Private Keys in HTTP Headers (server_sse.py:195-197, wiki/mcp/remote-server.md:1842-1845)

    • Private keys transmitted in every HTTP request header create a significant attack surface
    • Even with HTTPS, headers are visible in:
      • Server logs (mitigated by sanitization, but still risky)
      • Proxy logs (if any reverse proxy is used)
      • Browser developer tools (if accessed via browser)
      • Railway/hosting platform logs
    • Recommendation: Consider implementing a session-based auth flow where credentials are exchanged once for a session token
  2. No Rate Limiting per IP/User (server_sse.py:166-167)

    • Rate limiting exists but appears to be global, not per-client
    • Shared public server could be abused by one user affecting all users
    • Recommendation: Implement per-IP or per-credential rate limiting
  3. CORS Configuration (server_sse.py:268-285)

    • Default CORS origins only include claude.ai and console.anthropic.com
    • allow_headers=["*"] is overly permissive
    • allow_credentials=True with wildcard headers is a security risk
    • Recommendation: Restrict allowed headers to specific credential headers needed

🟡 High Priority

  1. Credential Validation Timing (dr_manhattan/mcp/session/exchange_manager.py:298-330)

    • Credentials are only validated when used, not when received
    • Invalid credentials waste server resources
    • Recommendation: Add early validation in get_credentials_from_headers()
  2. Missing Request Size Limits

    • No apparent limit on request body size for POST /messages/
    • Could lead to memory exhaustion attacks
    • Recommendation: Add Starlette middleware to limit request size
  3. Error Message Information Leakage (server_sse.py:178-180)

    • Error responses include full exception details via translate_error()
    • May leak implementation details or stack traces
    • Recommendation: Review translate_error() to ensure it sanitizes technical details in production
  4. HTTPS Not Enforced in Code (server_sse.py:17)

    • Comment says "HTTPS required in production" but code doesn't enforce it
    • Easy to misconfigure in self-hosted deployments
    • Recommendation: Add middleware to reject non-HTTPS requests (except localhost) or warn loudly

Code Quality Issues

Architecture & Design

  1. Global State in Module (server_sse.py:147-148)

    • exchange_manager and strategy_manager as global singletons
    • Makes testing difficult and creates hidden dependencies
    • Recommendation: Consider dependency injection pattern
  2. Logger Monkey Patching (server_sse.py:59-121)

    • Complex logger patching before imports is fragile
    • If import order changes, patching breaks
    • Recommendation: Use proper logging configuration or a logging factory pattern
  3. Credentials Never Cached (exchange_manager.py:298-330)

    • Per-request credentials mean exchange instances are recreated frequently
    • Comment says "Create exchange without caching (each user has different credentials)"
    • High initialization cost (timeouts suggest exchanges are slow to initialize)
    • Recommendation: Consider short-lived credential caching with TTL (e.g., 5 minutes) keyed by credential hash

Error Handling

  1. Bare Exception Catching (server_sse.py:177)

    • except Exception as e: is too broad
    • Catches and hides programming errors
    • Recommendation: Catch specific exceptions, let others propagate
  2. Cleanup Handler Not Async (server_sse.py:304-309)

    • Signal handler calls sync function but cleanup is async
    • _shutdown_requested flag set but never checked
    • Recommendation: Properly integrate with Uvicorn's shutdown lifecycle

Code Clarity

  1. Unused Variable (server_sse.py:301)

    • _shutdown_requested is set but never read
    • Dead code should be removed
    • Recommendation: Remove if unused, or implement graceful shutdown
  2. Magic Numbers (server_sse.py:232)

    • Hardcoded version "0.0.2" in health check
    • Should come from pyproject.toml or package metadata
    • Recommendation: Use importlib.metadata.version('dr-manhattan')

CLAUDE.md Compliance

✅ Follows Guidelines

  • Uses UV for dependencies (Dockerfile:15)
  • Includes comprehensive tests (tests/mcp/test_server_sse.py)
  • Created wiki documentation (wiki/mcp/remote-server.md)

❌ Violates Guidelines

  1. Rule 4: Single Source of Truth (server_sse.py:82-83, Dockerfile:24-26)
    • Loads .env file in code: load_dotenv(env_path)
    • ENV vars in Dockerfile duplicate defaults in code
    • Per CLAUDE.md: "DO NOT place many variables in .env file. Place them in the code instead."
    • Recommendation: Remove .env loading, use code defaults or remove Dockerfile ENV declarations

Performance Considerations

  1. No Connection Pooling Visible

    • Multiple HTTP requests from same client recreate exchange instances
    • Exchanges may maintain their own HTTP clients
    • Impact: Higher latency and resource usage
    • Recommendation: Document expected performance characteristics
  2. Synchronous Operations in Async Handlers (server_sse.py:173)

    • handler(**arguments) appears synchronous
    • Blocks the event loop for long operations
    • Recommendation: Wrap blocking operations in asyncio.to_thread()

Testing

✅ Strengths

  • Good test coverage for security utilities
  • Tests skip gracefully when mcp package not installed
  • Tests validate credential extraction and masking

🟡 Gaps

  1. Missing Integration Tests

    • No tests for actual SSE connections
    • No tests for context variable credential passing
    • No tests for exchange instance creation with header credentials
    • Recommendation: Add integration tests using TestClient
  2. Missing Security Tests

    • No tests for rate limiting
    • No tests for CORS behavior
    • No tests for error message sanitization
    • Recommendation: Add security-focused test cases

Documentation

✅ Strengths

  • Excellent wiki documentation with examples
  • Clear security warnings
  • Multi-exchange configuration examples

🟡 Improvements Needed

  1. Missing Threat Model (wiki/mcp/remote-server.md)

    • Documentation should explicitly state security trade-offs
    • Users should understand risks of shared server vs local
    • Recommendation: Add "Security Considerations" section with threat model
  2. No Credential Rotation Guidance

    • What happens if credentials are compromised?
    • How to rotate keys?
    • Recommendation: Add operational security guidance

Recommendations Summary

Must Fix Before Merge

  1. Implement per-client rate limiting
  2. Restrict CORS allowed headers (remove wildcard)
  3. Fix CLAUDE.md compliance (remove .env loading or justify exception)
  4. Add HTTPS enforcement for production deployments
  5. Implement proper async cleanup handler

Should Fix Soon

  1. Add session-based authentication to reduce credential transmission
  2. Add request size limits
  3. Add integration and security tests
  4. Document security trade-offs and threat model
  5. Fix hardcoded version number

Nice to Have

  1. Implement credential caching for performance
  2. Refactor logger monkey patching
  3. Add credential rotation documentation

Positive Highlights

  • Excellent security utilities with proper credential masking
  • Comprehensive error handling and validation
  • Well-structured code separation (server_sse.py, security.py, definitions.py)
  • Thoughtful test coverage for security utilities
  • Good use of context variables for request-scoped credentials
  • Proper Dockerfile with layer caching optimization
  • Clear, helpful documentation

Conclusion

This PR adds valuable functionality but has security concerns that should be addressed before deploying to production with real user credentials. The code quality is generally good, but the security architecture needs hardening for a public-facing service handling financial credentials.

Recommendation: Address critical security issues before merge, especially around credential transmission, rate limiting, and CORS configuration.

guzus and others added 2 commits January 25, 2026 14:22
- CLI command option (claude mcp add)
- Global vs project configuration
- Verification step with /mcp

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@claude
Copy link

claude bot commented Jan 25, 2026

Pull Request Review: SSE-based MCP Server for Remote Deployment

Summary

This PR adds comprehensive SSE transport support for remote MCP server deployment, enabling users to connect to Dr. Manhattan from Claude Desktop/Code without local installation. The implementation is well-structured and demonstrates solid engineering practices.

Code Quality & Architecture ✅

Strengths:

  • Excellent code organization: The refactoring to extract tool definitions into tools/definitions.py eliminates code duplication between stdio and SSE transports
  • Consistent patterns: SSE server follows the same logger patching approach as the stdio server, maintaining architectural consistency
  • Good separation of concerns: Security utilities are properly isolated in utils/security.py
  • Context variables: Smart use of contextvars for per-request credential isolation in concurrent environments

Areas for improvement:

  1. Dockerfile optimization (Dockerfile:55): Consider using --no-dev flag with uv to avoid installing dev dependencies in production:

    RUN uv pip install --system --no-dev ".[mcp]"
  2. CORS configuration (server_sse.py:379-386): The default allowed origins only include claude.ai and console.anthropic.com, but MCP clients typically don't send Origin headers. The comment acknowledges this, but the implementation may be overly restrictive. Consider documenting this more clearly or using allow_origin_regex for better flexibility.

  3. Tool dispatch proxy (tools/__init__.py:709-728): The _ToolDispatchProxy class is clever but adds complexity. Since tool definitions are already lazily loaded, consider simplifying this or adding documentation explaining why the proxy pattern is necessary.

Security 🔒

Strong security implementation:

  • ✅ Credentials never stored on server (per-request only)
  • ✅ Sensitive headers fully redacted in logs (no partial exposure)
  • ✅ Transport-agnostic error messages (no HTTP header leakage)
  • ✅ Proper credential validation before exchange initialization
  • ✅ HTTPS enforcement documented

Security concerns:

  1. Critical: Health check exposes service details (server_sse.py:336-345):

    return JSONResponse({
        "status": "healthy",
        "service": "dr-manhattan-mcp",
        "transport": "sse",
        "version": "0.0.2",  # Version disclosure
    })

    Version disclosure can help attackers identify known vulnerabilities. Consider removing the version field or making it configurable.

  2. Medium: Root endpoint information disclosure (server_sse.py:348-369):
    The root endpoint returns detailed usage information including credential header names. While convenient for developers, this aids reconnaissance. Consider:

    • Requiring authentication to view this endpoint
    • Or moving this to documentation only
  3. Low: Healthcheck timing (Dockerfile:69):
    The healthcheck uses urllib.request.urlopen which could timeout and block. Consider adding an explicit timeout parameter.

  4. Documentation concern (wiki/mcp/remote-server.md:1994-1996):
    The security best practices section recommends using environment variables for credentials, but the configuration examples show hardcoded credentials in JSON files. This could lead users to commit secrets. Add a warning:

    **WARNING**: Never commit configuration files with real credentials to version control.
    Consider using environment variable substitution in your JSON config.

Test Coverage ✅

Excellent test coverage:

  • 342 lines of comprehensive tests in tests/mcp/test_server_sse.py
  • Tests properly skip when MCP package not installed
  • Good coverage of:
    • Credential extraction (multiple exchanges, case-insensitivity)
    • Credential masking (full redaction)
    • Credential validation (required fields, error messages)
    • Health check endpoint
    • Environment validation

Minor gaps:

  1. No integration tests for the actual SSE connection flow
  2. No tests for the context variable credential propagation
  3. No tests for the tool dispatch proxy

Recommendation: Add at least one integration test that verifies credentials flow through the context variable to the exchange manager.

Performance ⚡

Good performance considerations:

  • ✅ Dockerfile uses multi-stage pattern for layer caching
  • ✅ Rate limiting implemented
  • ✅ Async cleanup operations use asyncio.to_thread

Potential issues:

  1. Exchange instance creation (exchange_manager.py:546-586):
    Every request creates a new exchange instance when using context credentials. This means:

    • No connection pooling for SSE users
    • Repeated initialization overhead
    • WebSocket connections created/destroyed per request

    Impact: High latency for SSE users compared to local server users who benefit from cached instances.

    Recommendation: Consider implementing a short-lived LRU cache keyed by credential hash to reuse instances for the same user across requests.

  2. Logger fixing overhead (server_sse.py:197-232):
    The fix_all_loggers() function iterates all loggers on every import. This is fine for startup but seems excessive.

  3. CORS middleware (server_sse.py:388-396):
    CORS middleware runs on every request even though MCP clients don't typically send Origin headers. This is minor overhead but worth noting.

Best Practices Alignment 📋

Alignment with CLAUDE.md:

  • ✅ Rule 1: Code is focused and clean
  • ✅ Rule 3: Uses UV for dependency management
  • ✅ Rule 4: Environment variables in code (PORT, LOG_LEVEL in Dockerfile)
  • ❌ Rule 2: Created new documentation files without explicit need

Documentation concerns:
Per CLAUDE.md Rule 2 ("DO NOT create a new document"), this PR adds:

  • wiki/mcp/remote-server.md (237 lines)
  • Updates to wiki/README.md

While this documentation is valuable for users, it technically violates the project convention. Consider whether this exception is justified for a major new feature.

Bugs & Issues 🐛

  1. Port validation inconsistency (server_sse.py:440):

    if not (1 <= port <= 65535):
        raise ValueError(f"Port must be 1-65535, got {port}")

    This raises ValueError but catches it immediately and calls raise SystemExit(1), which bypasses proper error handling. The error message won't be displayed to stderr before exit.

  2. Missing error context (exchange_manager.py:630):
    When creating per-request exchanges fails, the error doesn't indicate it was an SSE request. This makes debugging harder. Consider wrapping the exception with additional context.

  3. Signature type fallback (security.py:1343):

    except ValueError:
        exchange_creds[cred_key] = 0  # Default EOA

    Silent fallback to EOA could mask configuration errors. Consider logging a warning when this fallback occurs.

Additional Recommendations

  1. Add request ID logging: For debugging SSE issues, add a request ID to each SSE connection and log it with all operations.

  2. Metrics endpoint: Consider adding a /metrics endpoint (protected by auth) for monitoring request rates, error rates, and active connections.

  3. Rate limiting per-user: Current rate limiting is global. Consider implementing per-credential-hash rate limiting to prevent one user from affecting others.

  4. Connection limits: Document and enforce maximum concurrent SSE connections to prevent resource exhaustion.

  5. Credential rotation: Add documentation on how users can rotate credentials (they need to update their config and restart Claude).

Conclusion

This is a high-quality PR that adds significant value to the project. The implementation is solid, well-tested, and follows good security practices. The main concerns are:

  1. Performance impact of per-request exchange creation for SSE users
  2. Minor security hardening opportunities (version disclosure, information exposure)
  3. Potential violation of CLAUDE.md Rule 2 regarding documentation

Recommendation: ✅ Approve with minor fixes

The identified issues are not blockers, but addressing the performance concern (#1) and security hardening (#1-2) would significantly improve the production readiness of this feature.

Great work on this implementation! 🚀

@claude
Copy link

claude bot commented Jan 25, 2026

Pull Request Review: SSE MCP Server for Remote Deployment

Summary

This is a well-architected addition that enables remote access to Dr. Manhattan via SSE transport. The implementation demonstrates strong security awareness, good code organization, and thorough testing. Overall, this is production-ready code with a few recommendations for improvement.


Code Quality & Best Practices

Strengths

  1. Excellent Security Design

    • Full credential masking in logs (no partial exposure)
    • Context-based credential handling prevents credential caching
    • Sanitization of error messages to prevent credential leaks
    • Comprehensive test coverage for security utilities
  2. Good Separation of Concerns

    • tools/definitions.py consolidates tool definitions (DRY principle)
    • Security utilities isolated in dedicated module
    • Transport-agnostic error messages (proper abstraction)
  3. Solid Testing

    • 342 lines of tests covering critical paths
    • Proper handling of optional MCP dependency
    • Security-focused test coverage
  4. Follows CLAUDE.md Guidelines

    • Uses UV for dependency management (rule 3)
    • Single source of truth for configuration (rule 4)
    • Clean, focused code without unnecessary files (rules 1-2)

Areas for Improvement

1. Security: CORS Configuration May Be Too Permissive

Location: server_sse.py:265-285

Issue:

  • allow_headers=["*"] permits any header, including potentially dangerous ones
  • allow_credentials=True with broad origins can enable CSRF attacks

Recommendation:
Explicitly whitelist only required headers instead of using wildcard.

Priority: High - CORS misconfiguration is a common security vulnerability


2. Bug: Unused cleanup_handler Function

Location: server_sse.py:304-310, 346-347

Issue: Signal handlers are registered but the cleanup() async function is never called. The cleanup_handler sets a flag but doesn't trigger actual cleanup.

Recommendation:
Either call cleanup synchronously in the signal handler, or use Starlette's lifespan events for proper async cleanup.

Priority: High - This is a functional bug that prevents proper resource cleanup


3. Performance: Missing Request Timeout

Location: server_sse.py:354-360

Issue: No timeouts configured for uvicorn server, which can lead to resource exhaustion.

Recommendation:
Add timeout_keep_alive, limit_concurrency, and timeout_graceful_shutdown parameters to uvicorn.run()

Priority: Medium - Important for production stability


4. Missing: Rate Limiting Per User

Location: server_sse.py:166-167, call_tool() function

Issue: For a multi-tenant SSE server, rate limiting should be per-user/credential to prevent one user from exhausting resources.

Recommendation:
Implement per-user rate limiting using hashed credentials as user identifier.

Priority: Medium - Important for fair resource allocation


5. Code Quality: Logger Monkey-Patching is Fragile

Location: server_sse.py:30-122

Issue: Complex logger patching at module level is error-prone. The fix_all_loggers() function could interfere with third-party library logging.

Recommendation:
Add documentation explaining why this is necessary and add safeguards to exclude critical third-party loggers.

Priority: Medium - Works currently but technical debt


6. Documentation: Missing Deployment Security Guide

Location: wiki/mcp/remote-server.md

Issue: Documentation is excellent for setup but lacks security best practices for self-hosting.

Recommendation:
Add a production deployment security checklist covering HTTPS, CORS, firewall rules, credential rotation, monitoring, etc.

Priority: Medium - Important for users who self-host


Performance Considerations

Good Practices

  • Async/await properly used throughout
  • Context variables avoid thread-local storage issues
  • Lazy imports for optional dependencies

Suggestions

  • Consider connection pooling for exchange API clients to reduce latency
  • Market data could be cached with short TTL to reduce exchange API calls

Test Coverage

Strong Coverage

  • Security utilities: Comprehensive
  • Credential extraction: Thorough
  • Environment validation: Good

Missing Tests

  • No tests for actual SSE connection flow
  • No tests for concurrent requests with different credentials
  • Missing tests for network failures and timeouts

Final Recommendations

Must Fix (Before Merge)

  1. Fix cleanup handler bug (Priority: High)
  2. Restrict CORS headers (Priority: High)

Should Fix (Soon After Merge)

  1. Add request timeouts to uvicorn
  2. Implement per-user rate limiting
  3. Add production security documentation
  4. Consider refactoring logger patching

Nice to Have

  1. Add SSE integration tests
  2. Implement connection pooling
  3. Add caching for market data

Conclusion

This is high-quality, production-ready code with strong security awareness. The architecture is sound, testing is comprehensive for core functionality, and it follows the project's guidelines well.

The critical issues are minor and easily addressable. Once the cleanup handler bug and CORS configuration are fixed, this is ready to merge.

Recommendation: Approve with minor changes requested

Great work on this feature!

Security improvements for SSE server:
- Write operations (create_order, cancel_order, etc.) only allowed for Polymarket
- Other exchanges are read-only for security (no private keys on server)
- Polymarket uses Builder profile: API key, secret, passphrase (no private key)
- Updated tests and documentation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@claude
Copy link

claude bot commented Jan 25, 2026

Pull Request Review: SSE-based MCP Server for Remote Deployment

Summary

This PR adds a production-ready SSE (Server-Sent Events) transport for remote MCP server deployment, enabling users to connect to Dr. Manhattan from Claude Desktop/Code without local installation. The implementation is well-structured with strong security considerations.

Code Quality Assessment: ⭐⭐⭐⭐ (4/5)

Strengths

1. Excellent Security Design

  • Credential Masking: Full redaction of sensitive headers in logs (no partial exposure)
  • Write Operation Restrictions: Polymarket-only via Builder profile (no private keys on server)
  • Transport-Agnostic Error Messages: Clean separation between security logic and transport layer
  • Sensitive Pattern Detection: Regex-based filtering of private keys in error messages
  • HTTPS Enforcement: CORS configuration assumes production HTTPS

2. Clean Architecture

  • Shared Tool Definitions: tools/definitions.py eliminates duplication between stdio and SSE servers
  • Context-Based Credentials: contextvars for per-request credential injection
  • Lazy Loading: Tool definitions loaded on-demand to avoid import issues
  • Separation of Concerns: Security utilities cleanly separated from server logic

3. Comprehensive Testing

  • 372 lines of tests covering all security utilities
  • Tests for credential extraction, masking, validation, and write operation restrictions
  • Proper use of pytest.skipif for optional MCP package dependency

4. Documentation

  • Extensive wiki documentation (wiki/mcp/remote-server.md)
  • Clear setup instructions for both Claude Code and Claude Desktop
  • Security model clearly explained
  • Comparison table (local vs remote server)

5. Production Ready

  • Dockerfile: Multi-stage build with proper layer caching
  • Health Checks: Both Docker and HTTP endpoint
  • Environment Validation: Port range checking, log level validation
  • Graceful Shutdown: Signal handlers for SIGINT/SIGTERM
  • Error Handling: Try-finally blocks for context variable cleanup

Issues & Recommendations

🔴 CRITICAL: Security Vulnerability

Location: dr_manhattan/mcp/session/exchange_manager.py:305-319

The credential validation logic contains a security mismatch:

# SSE mode validation expects private_key + funder
if exchange_name.lower() == "polymarket":
    if not exchange_creds.get("private_key"):
        raise ValueError("Missing private_key credential...")
    if not exchange_creds.get("funder"):
        raise ValueError("Missing funder credential...")

But security.py:154 defines Builder profile requirements:

required_fields = {
    "polymarket": ["api_key", "api_secret", "api_passphrase"],
}

Impact: Users providing Builder profile credentials (api_key, api_secret, passphrase) will fail validation because the code checks for private_key instead.

Fix: Update exchange_manager.py:304-314 to check for Builder profile credentials:

if exchange_name.lower() == "polymarket":
    # Builder profile credentials (SSE mode - no private key)
    if not exchange_creds.get("api_key"):
        raise ValueError("Missing api_key credential...")
    if not exchange_creds.get("api_secret"):
        raise ValueError("Missing api_secret credential...")
    if not exchange_creds.get("api_passphrase"):
        raise ValueError("Missing api_passphrase credential...")

🟡 MAJOR: Potential Issues

1. Logger Patching Fragility (server_sse.py:36-100)

The logger patching logic is complex and fragile:

  • Patches happen at module import time
  • fix_all_loggers() removes ALL handlers from ALL loggers
  • Multiple patching steps (logger_module, dr_manhattan.utils)

Risk: This approach may cause issues with third-party libraries (starlette, uvicorn) that configure their own logging.

Recommendation:

  • Use logging.getLogger(__name__) consistently instead of patching
  • Configure only the root logger or dr_manhattan namespace
  • Consider using logging.config.dictConfig() for cleaner setup

2. CORS Configuration Too Permissive (server_sse.py:409-416)

allow_headers=["*"],  # ⚠️ Allows ALL headers
allow_credentials=True,

Risk: Allowing all headers with credentials enabled can expose sensitive data in cross-origin scenarios.

Recommendation:

allow_headers=[
    "Content-Type",
    "X-Polymarket-Api-Key",
    "X-Polymarket-Api-Secret", 
    "X-Polymarket-Passphrase",
],

3. Missing Rate Limiting Configuration (server_sse.py:281)

While check_rate_limit() is called, there's no configuration for:

  • Rate limit thresholds
  • Per-user vs global limits
  • Burst handling

Recommendation: Add environment variables for rate limit configuration and document them.

4. Context Variable Memory Leak Risk (server_sse.py:318-326)

While the code uses try-finally for cleanup, there's a subtle risk:

token = _request_credentials.set(credentials)
try:
    async with sse_transport.connect_sse(...):
        await mcp_app.run(...)
finally:
    _request_credentials.reset(token)

Risk: If the connection is long-lived, the context variable holds credentials in memory longer than necessary.

Recommendation: Consider adding a timeout or periodic credential refresh mechanism.


🟢 MINOR: Best Practice Improvements

1. Type Hints Inconsistency

  • Most functions use modern tuple[bool, Optional[str]] (PEP 604)
  • Some use Tuple[Callable, bool] (older style)

Fix: Use consistent modern style throughout (PEP 604 lowercase tuple).

2. Environment Variable Documentation

The Dockerfile sets defaults but doesn't document:

  • CORS_ALLOWED_ORIGINS
  • Rate limit settings
  • Other potential env vars

Fix: Add a table to wiki/mcp/remote-server.md documenting all env vars.

3. Dockerfile HEALTHCHECK URL

CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8080/health')"

Issue: Hardcoded port 8080 doesn't respect $PORT variable.

Fix:

HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
    CMD python -c "import os, urllib.request; urllib.request.urlopen(f'http://localhost:{os.getenv(\"PORT\", \"8080\")}/health')"

4. Test Coverage for Context Credentials

While security utilities are well-tested, there are no integration tests for:

  • Context credential injection in actual requests
  • Per-request credential isolation
  • Cleanup on connection close

Recommendation: Add integration tests using Starlette's TestClient.

5. Unused Function (security.py:208-226)

get_header_hint_for_credential() is defined but never called.

Action: Either use it in error messages or remove it.


Performance Considerations

Good

  • Lazy Tool Loading: Avoids importing MCP package until needed
  • Singleton Pattern: Exchange manager prevents duplicate instances
  • Docker Layer Caching: Dependencies cached separately from code

⚠️ Potential Concerns

  1. Per-Request Exchange Creation: SSE mode creates new exchange instances per request (line 236-276). This could be slow for high-traffic scenarios.

    • Impact: Each request initializes a new connection
    • Mitigation: Consider caching exchanges by credential hash
  2. Thread Pool Usage: _run_with_timeout uses ThreadPoolExecutor but doesn't limit pool size

    • Risk: Under load, could create excessive threads
    • Fix: Add max_workers parameter

Test Coverage Analysis

Coverage: ~85% (estimated)

Well Covered:

  • ✅ Credential extraction and masking
  • ✅ Write operation validation
  • ✅ Security utilities
  • ✅ Health endpoints

Missing Coverage:

  • ❌ SSE connection handling (handle_sse)
  • ❌ Message endpoint (handle_messages)
  • ❌ Context credential injection end-to-end
  • ❌ Error translation with credentials

Recommendation: Add integration tests for SSE endpoints using TestClient.


Adherence to CLAUDE.md Guidelines

Rule Status Notes
1. Focused, clean, easy to understand No emojis, clear structure
2. Don't create unnecessary docs Wiki docs are essential for feature
3. Only use UV Dockerfile uses UV correctly
4. Single Source of Truth (no .env) ⚠️ Uses env vars but documented
5. Run and Debug proactively Railway deployment tested
6. Exchange wiki template N/A Not adding exchange

Final Recommendations

Before Merge:

  1. FIX CRITICAL: Update credential validation in exchange_manager.py to use Builder profile fields
  2. FIX MAJOR: Restrict CORS allow_headers to specific headers
  3. FIX MINOR: Update Dockerfile HEALTHCHECK to respect $PORT

Post-Merge:

  1. Add integration tests for SSE endpoints
  2. Simplify logger patching logic
  3. Add rate limit configuration documentation
  4. Consider credential caching for performance

Verdict: Approve with Required Changes⚠️

This is a high-quality implementation with excellent security design and documentation. The critical credential validation bug must be fixed before merge, but the overall architecture is solid. Once the required fixes are applied, this will be a production-ready feature.

Estimated Risk: Medium (due to critical bug, but easily fixable)
Code Maintainability: High
Security Posture: High (after fixes)

Great work on this feature! The security-first approach and comprehensive documentation are particularly impressive. 🚀

- Create separate PolymarketBuilder class that uses API credentials
  (api_key, api_secret, passphrase) instead of private keys
- Update exchange_manager to route to PolymarketBuilder when Builder
  credentials are provided in SSE mode
- Add detailed step-by-step guide for getting Polymarket API credentials
- Add tests for PolymarketBuilder class

This enables secure trading on the remote MCP server without exposing
private keys. Users provide Builder profile credentials via HTTP headers.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@claude
Copy link

claude bot commented Jan 25, 2026

Pull Request Review: SSE-based MCP Server for Remote Deployment

Overview

This PR adds significant functionality for remote MCP deployment via SSE transport. The implementation is well-structured and follows security best practices. Below is my detailed review:


Code Quality & Best Practices

Strengths

  1. Security-First Design

    • Excellent use of Builder profile for Polymarket (no private keys exposed)
    • Proper credential masking in logs (fully redacted, not partial)
    • Context-aware credentials via contextvars for thread-safety
    • Write operations restricted to Polymarket only via SSE
  2. Clean Architecture

    • Good separation of concerns (security utils, session management, server logic)
    • Shared tool definitions between stdio and SSE servers
    • Proper use of singleton pattern for ExchangeSessionManager
  3. Follows CLAUDE.md Guidelines

    • Uses UV for dependency management (Dockerfile:9)
    • Config defaults in code, not .env (CLAUDE.md fix: polymarket impl #4)
    • Clean, focused codebase
  4. Comprehensive Testing

    • 372 lines of tests for SSE server
    • 85 lines for PolymarketBuilder
    • Good coverage of credential extraction, validation, masking, and write restrictions

Issues & Concerns

Critical

1. Credentials in Memory (Security)

  • Location: dr_manhattan/mcp/session/exchange_manager.py:144
  • Issue: MCP_CREDENTIALS global dict stores credentials for application lifetime
  • Risk: Memory dump could expose credentials
  • Recommendation: Consider using secure memory (e.g., mlock via ctypes) or credential rotation
  • Mitigation: Current _zeroize_credentials() provides defense-in-depth but doesn't guarantee immediate memory clearing

2. Missing Rate Limiting Implementation

  • Location: dr_manhattan/mcp/server_sse.py:169
  • Issue: check_rate_limit() is called but implementation not reviewed
  • Concern: Remote server needs proper rate limiting to prevent abuse
  • Action Required: Verify rate limiting is properly implemented with per-user/IP tracking

3. CORS Configuration

  • Location: dr_manhattan/mcp/server_sse.py:287-294
  • Issue: Default CORS allows claude.ai and console.anthropic.com but env var can override
  • Risk: Misconfigured CORS_ALLOWED_ORIGINS could allow unauthorized origins
  • Recommendation: Add validation for CORS origins to prevent wildcards (*)

Major

4. Timeout Handling

  • Location: dr_manhattan/mcp/session/exchange_manager.py:56-88
  • Issue: _run_with_timeout() uses ThreadPoolExecutor with cancel_futures=True
  • Concern: Abrupt cancellation may leave exchange connections in inconsistent state
  • Recommendation: Add graceful cleanup for cancelled futures

5. Error Message Sanitization

  • Location: dr_manhattan/mcp/utils/security.py:80-93
  • Issue: sanitize_error_message() uses regex patterns but isn't called in error paths
  • Gap: Error messages in server_sse.py:188 use translate_error() but may not sanitize private keys
  • Action Required: Verify all error paths sanitize sensitive data before returning to client

6. Context Variable Cleanup

  • Location: dr_manhattan/mcp/server_sse.py:206-214
  • Issue: Context variables are reset in finally blocks
  • Concern: If an exception occurs during reset, credentials remain in context
  • Recommendation: Use try/except around reset to ensure cleanup even on error

Minor

7. Verbose Mode Hardcoded

  • Location: dr_manhattan/mcp/session/exchange_manager.py:53
  • Issue: DEFAULT_VERBOSE = False is hardcoded
  • Comment: Good practice for MCP (prevents stdout corruption), but could be env-configurable for debugging

8. Health Check

  • Location: Dockerfile:29-30
  • Issue: Uses urllib.request.urlopen() without timeout
  • Risk: Health check could hang indefinitely
  • Fix: Add timeout parameter

9. Logger Patching

  • Location: dr_manhattan/mcp/server_sse.py:62-124
  • Issue: Complex monkey-patching of logger module before imports
  • Concern: Fragile and hard to maintain
  • Recommendation: Consider using logging configuration files or environment-based configuration

10. Type Hints

  • Location: Various files
  • Observation: Inconsistent use of type hints (e.g., Dict[str, Any] vs dict[str, Any])
  • Recommendation: Use modern Python 3.10+ syntax (dict, list) consistently

Performance Considerations

  1. Connection Pooling

    • RPC session cleanup implemented (_cleanup_rpc_session())
    • ExchangeClient caching prevents repeated initialization
  2. Docker Layer Caching

    • Dependencies installed before source copy (Dockerfile:14)
    • Good layer optimization
  3. Potential Issues:

    • No connection limits: SSE server doesn't limit concurrent connections
    • No request queuing: Could be overwhelmed by concurrent tool calls
    • Recommendation: Add connection pooling/limiting via middleware

Security Concerns

Addressed ✓

  • Credentials never logged
  • Write operations restricted to Polymarket
  • Transport-agnostic error messages (no HTTP header exposure)
  • HTTPS required in production (documented)

Needs Attention ⚠️

  1. Missing Input Validation

    • arguments dict in call_tool() (server_sse.py:176) not validated before use
    • Could lead to injection attacks if tool handlers don't validate inputs
    • Recommendation: Add JSON schema validation for tool arguments
  2. No Authentication/Authorization

    • Anyone with URL can access read-only features
    • No user authentication for write operations (only credential validation)
    • Consideration: Is this intentional? May want API keys for usage tracking
  3. Credential Transmission

    • Credentials sent via HTTP headers on every request
    • Recommendation: Document HTTPS requirement prominently
    • Enhancement: Consider session tokens after initial auth
  4. Secret Management

    • Production deployment needs secure secret storage
    • Recommendation: Document use of Railway secrets/env vars

Test Coverage

Good Coverage ✓

  • Credential extraction (case-insensitive, partial)
  • Credential masking (empty, sensitive headers)
  • Write operation validation
  • Health check endpoint

Missing Tests ⚠️

  1. Integration Tests

    • No tests for actual SSE connection flow
    • No tests for context credential injection
    • No tests for concurrent requests
  2. Error Scenarios

    • Network timeouts
    • Invalid credentials (401 responses)
    • Rate limit exceeded
  3. Edge Cases

    • Empty/malformed headers
    • Large request payloads
    • WebSocket disconnections

Documentation

Strengths ✓

  • Comprehensive README updates
  • Clear wiki documentation (wiki/mcp/remote-server.md)
  • Good examples for Claude Code and Claude Desktop

Suggestions

  1. Add deployment guide (Railway, Docker, environment variables)
  2. Document rate limits and usage quotas
  3. Add troubleshooting section
  4. Security best practices (HTTPS, credential rotation)

Recommendations

High Priority

  1. Verify rate limiting implementation - Critical for remote server
  2. Add input validation - Prevent injection attacks
  3. Fix health check timeout - Prevent Docker health check hangs
  4. Document HTTPS requirement - Security critical

Medium Priority

  1. Add connection limiting middleware
  2. Implement proper error sanitization in all paths
  3. Add integration tests for SSE flow
  4. Consider session-based auth for repeated requests

Low Priority

  1. Modernize type hints
  2. Simplify logger configuration
  3. Make verbose mode configurable via env var

Conclusion

This is a well-implemented feature that adds significant value to the project. The security model is sound, the architecture is clean, and the code follows best practices. The main concerns are around:

  1. Rate limiting (needs verification)
  2. Input validation (missing)
  3. Production security documentation (needs enhancement)

Recommendation: ✅ Approve with minor changes

The critical security measures are in place. The suggested improvements are mostly hardening and documentation. This PR is ready to merge after addressing the high-priority items.


Great work on the Builder profile integration and security-first approach! 🎯

guzus added 2 commits January 25, 2026 18:57
- Add detailed documentation explaining MCP servers and Operator Mode
- Explain security model (what operator can/cannot do)
- Show contract addresses with PolygonScan links
- Integrate wallet approval steps with explanations
- Add FAQ section addressing common concerns
- Style with clear visual hierarchy and info cards
@claude
Copy link

claude bot commented Jan 25, 2026

PR Review: SSE-based MCP Server for Remote Deployment

Executive Summary

This PR adds significant functionality for remote MCP deployment, but has several critical issues that need addressing before merge. Overall assessment: 3/5 - Good implementation with critical violations that must be fixed.


🔴 CRITICAL Issues (Must Fix Before Merge)

1. CLAUDE.md Rule 4 Violation: Environment Variables

Issue: The codebase rule explicitly states:

"Single Source of Truth: DO NOT place many variables in .env file. Place them in the code instead."

Yet this PR heavily relies on environment variables:

  • dr_manhattan/mcp/server_sse.py: PORT, LOG_LEVEL, HOST, CORS_ALLOWED_ORIGINS
  • dr_manhattan/exchanges/polymarket_operator.py: POLYMARKET_OPERATOR_KEY, POLYMARKET_OPERATOR_ADDRESS
  • Dockerfile: Multiple ENV declarations

Fix Required: Replace environment variables with:

  • Hard-coded defaults in code
  • Command-line arguments for server configuration
  • Configuration constants in dedicated config module

2. Docker Security: Running as Root

Location: Dockerfile

Issue: Container runs as root user (no USER directive), creating privilege escalation risk.

Fix Required:

# Add after installing dependencies, before CMD
RUN addgroup --system --gid 1001 appuser && \
    adduser --system --uid 1001 --gid 1001 appuser
USER appuser

3. CORS Security Issue

Location: dr_manhattan/mcp/server_sse.py:1995-2010

Issue:

allow_credentials=True,
allow_headers=["*"],  # ⚠️ Allows ANY header with credentials

This combination is a security risk - allows any header to be sent with credentials.

Fix Required: Restrict to specific headers:

allow_headers=["Content-Type", "X-Polymarket-Private-Key", "X-Polymarket-Chain-Id", ...],

4. HTTP-Specific Errors in Exchange Manager

Location: dr_manhattan/mcp/session/exchange_manager.py:960-986

Issue: Exchange manager has HTTP-specific error messages (mentions "headers"), coupling it to SSE transport:

raise ValueError(
    "Missing X-Polymarket-Private-Key header. "  # HTTP-specific!
    "Please include your private key in the request headers."
)

Fix Required: Use generic error messages:

raise ValueError("Missing required credential: private_key")

Let the SSE server translate to HTTP-specific messages.


🟡 HIGH Priority (Should Fix)

5. Scope Creep: Website Frontend

The PR adds 20+ website files (React/TypeScript/Vite, 1,893 lines of CSS) not mentioned in the PR title or main description. This significantly increases review complexity.

Recommendation: Move website to separate PR for clearer review and git history.

6. No HTTPS Enforcement

Location: dr_manhattan/mcp/utils/security.py:1175-1212

Credentials are passed via HTTP headers but there's no validation that HTTPS is being used in production.

Recommendation: Add explicit HTTPS check:

if not request.url.scheme == "https" and os.getenv("ENV") == "production":
    raise ValueError("Credentials can only be sent over HTTPS")

7. Silent Type Coercion Failure

Location: dr_manhattan/mcp/utils/security.py (signature_type parsing)

try:
    exchange_creds[cred_key] = int(value)
except ValueError:
    exchange_creds[cred_key] = 0  # Silently defaults - masks errors

Recommendation: Raise exception instead of silent default to catch configuration errors.


🟢 MEDIUM Priority (Consider Fixing)

8. Missing Connection Management

No visible timeout or connection limits for long-lived SSE connections. Could exhaust server resources under load.

Recommendation: Add connection timeout (e.g., 1 hour) and max connections limit.

9. Dictionary Mutation Bug

Location: dr_manhattan/mcp/session/exchange_manager.py:932-942

def _create_exchange_with_credentials(self, exchange_name: str, config_dict: Dict[str, Any]):
    config_dict["verbose"] = DEFAULT_VERBOSE  # Modifies input dict

Fix: Create copy: config_dict = {**config_dict, "verbose": DEFAULT_VERBOSE}

10. Missing Integration Tests

Good unit test coverage, but no end-to-end tests for:

  • SSE connection flow
  • Credential-based authentication
  • CORS behavior
  • Rate limiting

✅ STRENGTHS

  1. Excellent Code Organization: Great refactoring with tools/definitions.py - eliminated 348-line duplication
  2. Security Awareness: Credential sanitization improved to full masking (no partial exposure)
  3. Write Operation Restrictions: Clear allow-list for write-enabled exchanges
  4. Docker Layer Caching: Optimized Dockerfile for fast rebuilds
  5. UV Compliance: Correctly uses UV for dependency management (CLAUDE.md Rule 3 ✅)
  6. Good Test Coverage: 372 lines of SSE tests, Builder/Operator tests

Ratings

  • Code Quality: ⭐⭐⭐⭐☆ (4/5) - Well-structured, but violates project rules
  • Security: ⭐⭐⭐☆☆ (3/5) - Good awareness, critical issues need fixing
  • Testing: ⭐⭐⭐⭐☆ (4/5) - Good unit tests, missing integration tests
  • Architecture: ⭐⭐⭐⭐⭐ (5/5) - Excellent separation of concerns
  • CLAUDE.md Compliance: ⭐⭐☆☆☆ (2/5) - Critical violation of Rule 4

Overall: ⭐⭐⭐☆☆ (3/5) - Good work, but needs fixes before merge


Action Items

Required for Merge:

  1. ✅ Fix CLAUDE.md Rule 4: Remove environment variables, use code-based config
  2. ✅ Fix Docker security: Add non-root user
  3. ✅ Fix CORS: Restrict allow_headers to specific list
  4. ✅ Fix exchange manager: Remove HTTP-specific error messages

Strongly Recommended:

  1. Split website frontend to separate PR
  2. Add HTTPS enforcement for credential endpoints
  3. Fix silent type coercion failures

Nice to Have:

  1. Add SSE connection timeout/limits
  2. Fix dictionary mutation bug
  3. Add integration tests

Great work on the architecture and refactoring! The code is well-organized and shows strong engineering practices. Once the critical issues are addressed, this will be a solid addition to the codebase.

@claude
Copy link

claude bot commented Jan 25, 2026

PR Review: SSE-based MCP Server for Remote Deployment

Overview

This PR adds substantial infrastructure for remote MCP deployment via SSE transport, including Docker support and multiple authentication methods for Polymarket. The implementation is well-structured with good security considerations.

Code Quality & Best Practices

Strengths

Clean architecture: Separation of concerns between server, security, exchange managers
Comprehensive testing: 372 lines of tests added for SSE server
Good documentation: Detailed docstrings and inline comments
Follows CLAUDE.md: Uses UV, config in code (not .env), proactive debugging
Thread-safety: Proper use of locks for singleton patterns and credential access
Security-conscious: Credential masking, full redaction in logs, no partial exposure

Areas for Improvement

1. Security: Rate Limiting is Per-Server, Not Per-User 🔴 CRITICAL

Location: dr_manhattan/mcp/utils/rate_limiter.py:137-171

The global rate limiter is shared across all users. A single user can exhaust the rate limit and deny service to others.

# Current: Single global instance
_rate_limiter: Optional[RateLimiter] = None

def check_rate_limit() -> bool:
    limiter = get_rate_limiter()  # Same instance for all users
    if not limiter.try_acquire():
        return False

Recommendation: Implement per-user rate limiting keyed by user address or IP:

  • Extract user identifier from credentials/headers
  • Maintain dict of rate limiters per user
  • Add cleanup for inactive users
  • Consider IP-based limiting as fallback for unauthenticated requests

2. Security: Operator Mode Missing Authentication Verification 🟡 HIGH

Location: dr_manhattan/mcp/session/exchange_manager.py:356-361

Operator mode validates signatures but doesn't verify the operator approval on-chain before allowing trades.

# Validates signature but not on-chain approval
if has_user_address and not has_private_key and not has_builder_creds:
    from ..utils.security import validate_operator_credentials
    is_valid, error = validate_operator_credentials(exchange_creds)
    if not is_valid:
        raise ValueError(error)

Location: dr_manhattan/exchanges/polymarket_operator.py:297-305

def check_operator_approval(self) -> bool:
    """Check if user has approved the operator."""
    # This would require checking the CTF Exchange contract
    # For now, we'll rely on order placement errors to detect this
    return True  # Assume approved, error on order if not

Recommendation:

  • Implement on-chain verification of operator approval via Web3
  • Cache approval status per user (with TTL)
  • Fail fast with clear error message if not approved
  • Prevents wasted gas and better UX

3. Security: CORS Configuration Too Permissive 🟡 MEDIUM

Location: dr_manhattan/mcp/server_sse.py:296-304

Middleware(
    CORSMiddleware,
    allow_origins=ALLOWED_ORIGINS,
    allow_methods=["GET", "POST", "OPTIONS"],
    allow_headers=["*"],  # Too permissive
    allow_credentials=True,
)

Issue: allow_headers=["*"] with allow_credentials=True is a security anti-pattern.

Recommendation: Explicitly list allowed headers:

allow_headers=[
    "Content-Type",
    "X-Polymarket-Api-Key",
    "X-Polymarket-Api-Secret", 
    "X-Polymarket-Passphrase",
    "X-Polymarket-Wallet-Address",
    "X-Polymarket-Auth-Signature",
    "X-Polymarket-Auth-Timestamp",
    "X-Polymarket-Auth-Expiry",
]

4. Potential Bug: Context Variable Not Reset on Exception 🟡 MEDIUM

Location: dr_manhattan/mcp/server_sse.py:197-216

async def handle_sse(request: Request) -> Response:
    credentials = get_credentials_from_headers(headers)
    token = _request_credentials.set(credentials)

    try:
        async with sse_transport.connect_sse(...) as streams:
            await mcp_app.run(...)
    finally:
        _request_credentials.reset(token)

    return Response()  # Unreachable if exception in try block

Issue: If an exception occurs before the async with, the finally block runs but then the exception propagates, leaving the Response unreachable. This is likely fine, but the control flow is unclear.

Recommendation: Make exception handling explicit or add comment explaining intended behavior.

5. Code Duplication: Three Similar Polymarket Classes 🔵 LOW

Files: polymarket.py, polymarket_builder.py, polymarket_operator.py

Significant code duplication in create_order, cancel_order, fetch_balance, fetch_open_orders methods. The main difference is client initialization.

Recommendation: Consider refactoring to use composition or a base class with a factory method for client creation. Not critical for this PR but worth noting for future maintenance.

6. Missing Input Validation 🔵 LOW

Location: dr_manhattan/mcp/utils/security.py:278-327

The verify_wallet_signature function doesn't validate the wallet address format before attempting signature verification.

Recommendation: Add Web3 address validation:

if not Web3.is_address(wallet_address):
    return False, "Invalid wallet address format."

Performance Considerations

Docker Image Optimization

Location: Dockerfile:1-34

Good: Multi-stage layer caching, slim base image
Good: Dependencies installed before code copy
Good: Proper use of uv per CLAUDE.md

Minor suggestion: Consider multi-stage build to reduce final image size:

FROM python:3.13-slim AS builder
# ... install deps ...

FROM python:3.13-slim
COPY --from=builder /usr/local/lib/python3.13/site-packages /usr/local/lib/python3.13/site-packages

Timeout Handling

Location: dr_manhattan/mcp/session/exchange_manager.py:46-87

Good: Proper timeout handling with ThreadPoolExecutor
Good: Cleanup with cancel_futures=True

The timeout values (10s exchange, 5s client) seem reasonable for remote deployment.

Security Concerns Summary

Severity Issue Impact
🔴 CRITICAL Global rate limiter allows DoS Single user can exhaust quota for all users
🟡 HIGH Missing on-chain operator approval check Users could attempt trades without approval
🟡 MEDIUM Permissive CORS headers Potential for header injection attacks
🟡 MEDIUM Context variable exception handling Unclear error propagation
🔵 LOW Missing address validation Minor - caught later in signature verification

Test Coverage

Excellent: 372 lines of SSE server tests
Good: Tests for credential extraction, masking, validation
Good: Tests for both Builder and Operator modes

Missing:

  • Integration tests for rate limiting behavior
  • Tests for concurrent requests with different credentials
  • Tests for CORS behavior
  • Tests for operator approval checking (when implemented)

Additional Observations

Website Changes (25 files)

Large number of website changes included. Consider whether these belong in a separate PR for easier review. The website files don't appear to have been reviewed in detail here.

Documentation

✅ Wiki documentation added for remote server setup
✅ Good inline comments explaining security model

Recommendations

Before Merging

  1. MUST FIX: Implement per-user rate limiting
  2. SHOULD FIX: Restrict CORS allowed headers
  3. CONSIDER: Add on-chain operator approval verification

Future Enhancements

  • Add metrics/monitoring for rate limit hits
  • Add request tracing for debugging
  • Consider Redis-backed rate limiting for multi-instance deployment
  • Add health check that validates operator key is set

Verdict

This is a well-engineered PR with good security practices overall. The critical issue with global rate limiting should be addressed before merging to prevent DoS scenarios. The CORS configuration should also be tightened.

After addressing the rate limiting issue and CORS headers, this will be ready to merge.

Estimated Risk: MEDIUM-HIGH (due to rate limiting DoS vector)
Recommended Action: Request changes for rate limiting and CORS, then approve


Great work on the comprehensive security model and clean architecture! 🚀

guzus added 2 commits January 25, 2026 19:05
- Change route from /approve to /mcp
- Add "Quick Start: Read-Only Mode" section with copy-paste config
- No wallet required for read-only market data access
- Rename "How it Works" to "Trading Mode Setup" for clarity
@claude
Copy link

claude bot commented Jan 25, 2026

PR Review: SSE-based MCP Server for Remote Deployment

Summary

Request changes - Critical issues found. This PR adds SSE transport for remote MCP deployment with good architecture but has critical security and configuration issues.

Critical Issues

1. Invalid Operator Address (website/src/wagmi.ts:32)

  • OPERATOR_ADDRESS is set to 0x0000000000000000000000000000000000000000 (zero address)
  • Users will approve a non-existent operator, breaking operator mode completely
  • Fix: Deploy server, derive address from POLYMARKET_OPERATOR_KEY, or remove operator mode

2. Signature Replay Vulnerability (dr_manhattan/mcp/utils/security.py)

  • Valid signatures can be replayed within expiry window (24h-90d)
  • No nonce tracking to prevent signature reuse
  • Fix: Implement nonce-based replay protection

3. Documentation/Implementation Mismatch

  • Server says Builder mode only, wiki says Operator mode primary, website implements Operator flow
  • Fix: Complete operator mode OR update docs to focus on Builder mode

High Priority Issues

4. Missing Operator Key Validation (polymarket_operator.py:70-74)

  • No startup validation of POLYMARKET_OPERATOR_KEY environment variable

5. No On-Chain Approval Validation (polymarket_operator.py:297-305)

  • check_operator_approval() always returns True without checking blockchain

6. Missing Operator Address Discovery

  • No API endpoint to expose operator address for client configuration

7. Error Handling Gaps (server_sse.py:197-232)

  • SSE handlers don't log or return errors properly

Positive Aspects

  • Excellent security utils with comprehensive credential sanitization
  • Thread-safe implementations with proper locking
  • Good test coverage for credential handling
  • Builder mode is production-ready and well-implemented
  • Consistent with CLAUDE.md (uses uv, single source of truth)
  • Docker optimization with layer caching
  • Rate limiting with token bucket algorithm

Recommendations

Block Merge:

  1. Fix OPERATOR_ADDRESS or remove operator mode
  2. Clarify primary authentication mode in docs
  3. Implement signature replay protection

Before Production:
4. Add startup validation for operator mode
5. Add operator address discovery endpoint
6. Improve error handling in SSE handlers
7. Implement on-chain approval validation

Conclusion

Solid architecture and high-quality implementation in most areas. The operator mode is incomplete - either finish it or pivot to Builder mode as primary. Address signature replay before merging.

@claude
Copy link

claude bot commented Jan 25, 2026

Pull Request Review

Summary

This is a substantial and well-structured PR that adds remote MCP deployment via SSE transport. Code quality is high, but there are several critical security concerns that must be addressed before merge.

Critical Issues (BLOCKERS)

1. SECURITY: Operator Mode Lacks On-Chain Approval Verification

Location: dr_manhattan/exchanges/polymarket_operator.py

The server uses POLYMARKET_OPERATOR_KEY to sign orders but does NOT verify that users have approved the operator on-chain via setApprovalForAll(). The signature verification only proves wallet ownership, not operator approval.

Recommendation: Add on-chain isApprovedForAll() check before accepting trading requests.

2. SECURITY: Missing Operator Address Validation

Location: dr_manhattan/exchanges/polymarket_operator.py:70-74

Operator address should be: (1) Derived from private key, (2) Logged on startup, (3) Provided to users for approval.

3. SECURITY: CORS Too Permissive

Location: dr_manhattan/mcp/server_sse.py:301

allow_headers=['*'] is too permissive. Use explicit allowlist.

4. Missing Wiki Documentation (CLAUDE.md Rule 6)

No wiki documentation at wiki/exchanges/polymarket_operator.md. Required per CLAUDE.md when adding new exchange.

High Priority Issues

5. Dockerfile Security Hardening

  • Running as root (no USER directive)
  • Should install uv via official method

6. Incomplete Environment Validation

_validate_env() doesnt validate POLYMARKET_OPERATOR_KEY or CORS_ALLOWED_ORIGINS.

7. Test Coverage Gaps

Missing tests for: signature expiry edge cases, operator approval verification, rate limiting, CORS handling.

8. Fragile Logger Patching

Complex monkey-patching violates CLAUDE.md rule 1 (clean, easy to understand). Use logging config instead.

Positive Aspects

  1. Excellent security-first design (credential sanitization, zeroization)
  2. Well-structured code with clear separation of concerns
  3. Comprehensive tests for core functionality
  4. Good documentation
  5. Follows CLAUDE.md (uses UV, avoids .env bloat)
  6. Innovative operator pattern

Recommendation

DO NOT MERGE until critical issues 1-4 are resolved. Once fixed, this will be an excellent addition.

Post-fix recommendations:

  • Security audit of operator mode
  • Load testing of SSE endpoint
  • Penetration testing of auth flow

Great work overall! The architecture is solid. Security issues are fixable and dont detract from the design quality.

@railway-app railway-app bot temporarily deployed to dr-manhattan-mcp / staging January 26, 2026 10:13 Inactive
@railway-app railway-app bot temporarily deployed to dr-manhattan-mcp / staging February 8, 2026 16:58 Inactive
@claude
Copy link

claude bot commented Feb 8, 2026

Comprehensive Code Review - PR #71

Overall Assessment: APPROVE WITH REQUIRED CHANGES

This is a well-engineered PR (11,732 additions, 4,034 deletions) that significantly improves the codebase architecture and adds valuable remote deployment capabilities. The Polymarket refactoring from a 1,930-line monolith into a modular package is excellent. However, several security issues and missing safeguards must be addressed before production use.


Blocking Issues (Must Fix Before Merge)

1. Operator Approval Not Verified

Location: dr_manhattan/exchanges/polymarket/polymarket_operator.py:305

Risk: HIGH - Orders attempted even if user has not approved operator on-chain
Impact: Failed orders, wasted gas, poor user experience
Fix: Implement proper on-chain approval check via CTF Exchange contract, or at minimum log a warning

2. Missing CTF Operation Tests

Status: No tests found for split/merge/redeem functionality
Risk: HIGH - Financial operations with no test coverage
Required: Add comprehensive tests covering split USDC, merge tokens, redeem positions, error handling, and signature verification

3. HMAC Body Serialization Bug

Location: dr_manhattan/exchanges/polymarket/polymarket_ctf.py:165

The code uses str(body).replace("'", '"') which does not match JSON format reliably. Python dict repr is not JSON.
Fix: Use proper JSON serialization with json.dumps(body, separators=(',', ':'))

4. Silent Exception Handling in CTF Relayer

Location: dr_manhattan/exchanges/polymarket/polymarket_ctf.py:256-258

Silent except Exception: pass in _poll_transaction hides network errors and transaction status.
Fix: Log exceptions and return error status to caller


High Priority (Before Production)

5. Operator Key Rotation Not Documented

Server-wide operator private key in POLYMARKET_OPERATOR_KEY has no rotation mechanism.
Recommendations: Document key rotation, consider secrets manager, add monitoring, implement periodic rotation

6. Rate Limiting Is Server-Wide Only

Current 10 calls/sec limit is per-server, not per-user. Multiple users can collectively exceed API rate limits.
Recommendation: Implement per-user rate limiting using IP or wallet address for SSE mode

7. Missing Integration Tests

Coverage gaps: PolymarketBuilder order flow (85 lines unit tests only), PolymarketOperator with mock approval (75 lines), SSE concurrent requests, rate limiter burst scenarios


Excellent Work

Architecture & Refactoring

Polymarket Package Split: Outstanding refactoring from 1,930-line monolith into clean modular structure with single responsibility per module. Import path unchanged for backward compatibility.

Security Implementation

  • Credential Masking: Excellent - full masking with [REDACTED], no partial exposure
  • CORS Configuration: Good - configurable origins with safe defaults
  • Signature Verification: Well-implemented with timestamp validation, expiry, replay protection, proper EIP-191
  • Input Validation: Comprehensive regex patterns for addresses, IDs, UUIDs - no injection risks

Test Coverage

SSE Server Tests (372 lines): Excellent coverage of credential extraction, masking, write restrictions, health check, environment validation

Docker & Deployment

Dockerfile: Excellent implementation following CLAUDE.md rules with layer caching, uv for dependencies, Python 3.13-slim, clever health check without curl


Security Checklist

Category Status Notes
Input Validation PASS Comprehensive regex validation, no injection risks
Authentication WARN Operator approval not verified on-chain
Credential Storage PASS Proper masking, no plaintext logging
CORS PASS Configurable origins with safe defaults
Rate Limiting WARN Server-wide only, not per-user
Error Handling WARN Some exceptions silently caught
Cryptography WARN HMAC bug needs fix, otherwise proper EIP-712
Secrets Management WARN Environment variables, no rotation documented

Code Metrics

  • Code Quality: 8/10 - Excellent refactoring, some error handling gaps
  • Security: 7/10 - Good credential management, missing operator verification
  • Test Coverage: 6/10 - Good utilities tests, missing critical CTF/integration tests
  • Documentation: 7/10 - Good inline docs, needs deployment guide improvements

Recommendations Summary

Must Fix (Blocking):

  1. Implement operator approval verification or add warning logs
  2. Add CTF operation test coverage
  3. Fix HMAC body serialization (json.dumps instead of str())
  4. Add exception logging in relayer polling

Should Fix (Before Production):

  1. Document operator key rotation procedures
  2. Implement per-user rate limiting for SSE
  3. Add integration tests for PolymarketBuilder/Operator
  4. Document CORS configuration requirements

Nice to Have:

  1. Add LRU cache for exchange instances
  2. Deprecate legacy signature format without expiry
  3. Add retry logic for relayer submissions
  4. Further split polymarket_gamma.py (1,208 lines)

Verdict

APPROVE pending the 4 blocking fixes. This PR represents significant architectural improvements and adds valuable remote deployment capabilities. The security model with Builder and Operator modes is well thought out. Address the blocking issues and document the security considerations, and this will be ready for production.

Great work on the modular refactoring! The code is much more maintainable now.

@minkyun12 minkyun12 force-pushed the feat/deploy-mcp-sse-server branch from c2b13bb to 7de2707 Compare February 8, 2026 17:04
@claude
Copy link

claude bot commented Feb 8, 2026

Pull Request Review: SSE-based MCP Server for Remote Deployment

Summary

This PR adds significant infrastructure for remote MCP server deployment via SSE transport, along with Polymarket Builder and Operator pattern support. Overall, the implementation is well-structured and production-ready, with strong security considerations. However, there are several areas that need attention before merging.


Critical Issues

1. Operator Mode Security Vulnerability (HIGH PRIORITY)

Location: dr_manhattan/exchanges/polymarket_operator.py:70

The operator mode stores a sensitive private key (POLYMARKET_OPERATOR_KEY) in environment variables on the server. This creates a single point of failure:

  • If the server is compromised, the operator key can trade on behalf of ALL users who have approved it
  • The key has unlimited trading authority for all approved users
  • No rate limiting or per-user spending caps

Recommendation: Add comprehensive documentation warning about this security model, implement per-user spending limits, and document the revocation process clearly.

2. Missing CORS Security in Production

Location: dr_manhattan/mcp/server_sse.py:287-294

The CORS configuration allows unrestricted override via env var with no HTTPS validation.

Recommendation: Add HTTPS validation for all CORS origins in production mode.

3. Signature Expiry Validation Gap

Location: dr_manhattan/mcp/utils/security.py:286-296

A 90-day signature expiry is too long for security. Clock skew tolerance is undocumented.

Recommendation: Document security tradeoffs and consider shorter defaults with warnings for long expiries.


Security Concerns

4. Credential Zeroization is Incomplete

Location: dr_manhattan/mcp/session/exchange_manager.py:161-179

Python strings are immutable, so setting to empty string doesn't overwrite memory. No gc.collect() call.

Recommendation: Add gc.collect() after zeroization to force memory cleanup.

5. Sensitive Data in Error Messages

Location: dr_manhattan/mcp/utils/security.py:106-119

Third-party library errors might leak credentials. Regex patterns don't cover all formats.

Recommendation: Wrap ALL external API calls in sanitizing try-except handlers.

6. No Rate Limiting Implementation Details

Location: dr_manhattan/mcp/server_sse.py:169

Rate limiting is called but implementation and strategy are not documented.

Recommendation: Document rate limiting strategy in wiki/mcp/remote-server.md


Code Quality Issues

7. Logger Monkey-Patching is Fragile

Location: dr_manhattan/mcp/server_sse.py:37-70

Import-order dependent patching is error-prone and hard to maintain.

8. Inconsistent Error Handling

Location: dr_manhattan/exchanges/polymarket_builder.py:169-170

Error messages vary between generic and specific formats.

9. Magic Numbers Without Constants

Timeout values (10.0s, 5.0s) and clock skew (300s) are hardcoded throughout.

10. Missing Input Validation

Location: dr_manhattan/exchanges/polymarket_builder.py:104-143

No validation of price bounds, size minimums, or market status.


Performance & Architecture

11. No Connection Pooling

Each ClobClient may create new connections leading to potential port exhaustion.

12. Timeout Strategy Needs Documentation

Timeout values aren't justified, no exponential backoff.

13. Singleton Pattern Complexity

The pattern could be simplified with a module-level instance.


Strengths

  1. Excellent separation of concerns
  2. Comprehensive test coverage for security features
  3. Strong security mindset throughout
  4. Good inline documentation
  5. Docker best practices followed
  6. Adheres to CLAUDE.md guidelines

Minor Issues

  1. Dockerfile could use multi-stage builds
  2. Health check could be more detailed
  3. Website /approve page needs rate limiting
  4. TODOs in cross_exchange/matcher.py should be tracked
  5. Inconsistent naming conventions
  6. Missing wiki/exchanges/polymarket.md per CLAUDE.md rule 6

Recommendations Before Merge

Must Fix (Blocking)

  1. Add HTTPS validation for CORS
  2. Document operator key security risks prominently
  3. Improve credential zeroization with gc.collect()
  4. Add comprehensive error message sanitization

Should Fix (High Priority)

  1. Extract magic numbers to constants
  2. Add input validation for order parameters
  3. Document rate limiting implementation
  4. Create wiki/exchanges/polymarket.md

Final Verdict

This PR represents significant, high-quality work with strong security considerations. The architecture is sound and follows best practices. However, the operator mode security model needs more documentation and safeguards before production deployment.

Recommendation: Request changes for critical security issues and documentation, then approve after fixes.

Great work overall! The remote MCP deployment is a powerful feature.

* Adds PM CTF split/merge/redeem functionality

Implements split, merge, and redeem operations for Conditional Token Framework (CTF) tokens on Polymarket.

Introduces new methods for splitting USDC into conditional tokens, merging them back, and redeeming winning tokens from resolved markets.

Leverages Polymarket's Builder API and relayer infrastructure for transaction submission and confirmation.

Adds helper functions for encoding transaction data and signing Safe transactions.

* refactor: split polymarket.py into mixin modules + add Data/Gamma/WebSocket APIs

- Split 2564-line monolith into 6 mixin files:
  - polymarket_core.py: constants, init, request helpers
  - polymarket_clob.py: CLOB API (orders, positions, balance)
  - polymarket_gamma.py: Gamma API (markets, search, tags)
  - polymarket_data.py: Data API (trades, analytics)
  - polymarket_ctf.py: CTF operations (split/merge/redeem)
  - polymarket_ws_ext.py: Sports/RTDS WebSocket

- New Gamma API methods: fetch_events, fetch_event, fetch_event_by_slug,
  fetch_series, fetch_series_by_id, fetch_comments, fetch_profile,
  fetch_sports_metadata

- New Data API methods: fetch_leaderboard, fetch_user_activity,
  fetch_top_holders, fetch_open_interest, fetch_closed_positions,
  fetch_accounting_snapshot

- New WebSocket: PolymarketSportsWebSocket, PolymarketRTDSWebSocket

- Import path unchanged: from dr_manhattan.exchanges.polymarket import Polymarket
- All existing function logic preserved as-is

* refactor: move polymarket modules into exchanges/polymarket/ package

- polymarket.py → polymarket/__init__.py
- All mixin files moved into polymarket/ directory
- Updated import paths (.. → ...) for package depth
- Fixed exchanges/__init__.py imports for Builder/Operator
- All imports verified working

* docs: update README with new polymarket package structure

* fix: correct leaderboard endpoint to /v1/leaderboard with proper params

- Fixed endpoint path: /leaderboard → /v1/leaderboard
- Added params: category, timePeriod, orderBy (from docs)
- Verified working with real API calls

* feat: add remaining CLOB/Gamma/Data/Bridge API endpoints

* fix: fetch_live_volume param name (eventId→id), fetch_supported_assets response parsing

- polymarket_data.py: fetch_live_volume used 'eventId' but API requires 'id'
- polymarket_bridge.py: fetch_supported_assets now handles {supportedAssets:[...]} response
- Added VERIFICATION_REPORT.md with full API verification results

* fix: add default side param to get_price()

* remove: drop non-working endpoints (batch CLOB, comments, profile, bridge status)

Polymarket API issues:
- /books, /prices, /spreads: batch endpoints disabled by Polymarket
- /comments: parameter format undocumented, always returns 422
- /profiles: requires authentication (401)
- /status/{addr}: server 500 error

* chore: remove broken fetch_accounting_snapshot endpoint

* feat: unify market identifiers - all market methods accept Market | str

- Add _resolve_condition_id, _resolve_gamma_id, _resolve_token_id helpers
- fetch_market() now accepts condition_id, token_id, gamma_id, slug, or Market
- get_price/get_midpoint/get_orderbook accept Market | str with outcome param
- fetch_token_ids/fetch_open_interest/fetch_top_holders accept Market | str
- split/merge/redeem accept Market | str
- fetch_market_tags accepts Market | str (auto-resolves gamma_id)
- _resolve_token_id handles condition_id (0x...) by fetching token_ids via CLOB

* feat: warn when multiple markets match in fetch_market

* docs: add comprehensive README for polymarket package

* chore: link polymarket docs in README, fix target-version to py311

* chore: remove test scripts and pycache

* chore: fix ruff lint errors and format polymarket package

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: guzus <storminggalaxys3@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
@railway-app railway-app bot temporarily deployed to dr-manhattan-mcp / staging February 9, 2026 02:30 Inactive
@claude
Copy link

claude bot commented Feb 9, 2026

PR #71 Code Review: Dr. Manhattan MCP Server & Polymarket Integration

Executive Summary

This PR represents a significant architectural refactoring and feature addition to Dr. Manhattan. It introduces:

  1. SSE-based remote MCP server for Claude Desktop/Code integration
  2. PolymarketBuilder & PolymarketOperator classes for server-side trading without private keys
  3. Comprehensive security framework for credential handling and signature verification
  4. Interactive website for wallet-based authentication
  5. Session management for stateful trading operations

Overall assessment: High quality implementation with solid security practices, though some edge cases and improvements are worth addressing.


Critical Issues (Fix Before Merge)

1. Global Variable Bug in reload_credentials() 🚨

File: dr_manhattan/mcp/session/exchange_manager.py:204

def reload_credentials(self) -> Dict[str, Dict[str, Any]]:
    ...
    MCP_CREDENTIALS = _get_mcp_credentials()  # This is a local assignment!

Issue: Missing global MCP_CREDENTIALS declaration - credentials won't actually reload.
Fix: Add global MCP_CREDENTIALS at the start of the function.


2. Print Statements Breaking MCP Protocol 🚨

Files:

  • dr_manhattan/exchanges/polymarket/polymarket_builder.py:256
  • dr_manhattan/exchanges/polymarket/polymarket_operator.py:282
if self.verbose:
    print(f"Warning: Failed to fetch open orders: {e}")

Issue: Print statements corrupt MCP JSON-RPC protocol (as documented in exchange_manager.py:50-52).
Fix: Replace with logger.warning().


3. Signature Message Format Needs Versioning 🔒

File: dr_manhattan/mcp/utils/security.py:307-311

if expiry:
    message = f"{AUTH_MESSAGE_PREFIX}\n\nWallet: {wallet_address}\nTimestamp: {timestamp}\nExpiry: {expiry}"
else:
    message = f"{AUTH_MESSAGE_PREFIX}\n\nWallet: {wallet_address}\nTimestamp: {timestamp}"

Issue: Hardcoded message format must match frontend exactly. If frontend changes, verification silently fails.
Fix: Add versioned message format or schema validation.


Important Issues (Should Fix)

4. Missing Wallet Address Format Validation

File: dr_manhattan/mcp/utils/security.py:340

user_address = credentials.get("user_address")
if not user_address:
    return False, "Missing wallet address."

Issue: Doesn't validate Ethereum address format (0x + 40 hex chars).
Fix: Add regex validation: ^0x[a-fA-F0-9]{40}$


5. No Per-User Audit Logging for Operator Trades

File: dr_manhattan/exchanges/polymarket/polymarket_operator.py:139-210

Issue: Operator mode lacks accountability - doesn't log which user initiated trades.
Fix: Add structured logging with user_address, timestamp, and order details.


6. Operator Key Never Zeroized from Memory

File: dr_manhattan/exchanges/polymarket/polymarket_operator.py:70

self._operator_key = os.getenv("POLYMARKET_OPERATOR_KEY")

Issue: Private key stored indefinitely in memory.
Fix: Implement __del__ cleanup or key zeroization on shutdown.


7. No Rate Limiting on Signature Verification

File: dr_manhattan/mcp/utils/security.py:261-327

Issue: Attackers could brute-force signatures with different addresses.
Fix: Add rate limiting to /messages/ POST endpoint.


8. Empty Credential String Validation Missing

File: dr_manhattan/mcp/utils/security.py:178-190

required_fields = {
    "polymarket": ["api_key", "api_secret", "api_passphrase"],
}

Issue: No validation that credential values aren't empty strings.
Fix: Add if not credentials.get(field) check for each required field.


Strengths 🎉

Security Excellence

  • ✅ Full credential masking in logs (no partial exposure)
  • ✅ Proper timestamp validation with clock skew tolerance
  • ✅ Safe context field allowlist for error messages
  • ✅ Builder profile avoids exposing private keys
  • ✅ CORS configuration with environment-based origins

Architecture Quality

  • ✅ Clean refactoring: Polymarket monolith → package with mixins
  • ✅ Thread-safe session management with locks
  • ✅ Proper context management using contextvars.ContextVar
  • ✅ Comprehensive error translation to MCP format
  • ✅ Clear separation of concerns (transport/session/tools)

Production Readiness

  • ✅ Dockerfile optimized with layer caching
  • ✅ Health check endpoint
  • ✅ Environment variable validation
  • ✅ Graceful shutdown handling
  • ✅ Comprehensive test coverage (13/13 passing)

User Experience

  • ✅ Excellent wallet connection UX (step-by-step guide)
  • ✅ Clear security documentation (can do / cannot do)
  • ✅ Read-only mode for no-auth exploration
  • ✅ RainbowKit for standard Web3 patterns

Additional Recommendations

Before Merging

  • Fix all 3 critical bugs listed above
  • Add missing validations (items 4-8)
  • Replace print() statements with logger calls
  • Add wallet address format validation

Testing Gaps to Address

  • SSE credential extraction/validation tests
  • Signature verification edge case tests
  • Operator mode approval checking tests
  • Integration tests with mocked Polymarket API

Nice-to-Have Improvements

  • Add localhost to CORS defaults for local development
  • Implement check_operator_approval() properly (currently stub at line 305)
  • Add environment-specific MCP server URL configuration to website
  • Add timeout handling on Builder client initialization
  • Contract address verification on frontend

Post-Merge / Future

  • Add structured JSON logging for monitoring
  • Add metrics (Prometheus format) for observability
  • Implement database for audit logging
  • Add request batching for multiple tool calls
  • Document credential rotation procedures

Security Review Summary

Threat Model:

  • ✅ Credentials masked in logs
  • ✅ Signature replay attacks mitigated (timestamp + expiry)
  • ⚠️ Brute force signature attempts (needs rate limiting)
  • ⚠️ Operator key in memory indefinitely (needs zeroization)

Authentication:

  • ✅ Multi-mode: Operator > Builder > Direct
  • ✅ Per-request credentials via HTTP headers
  • ⚠️ Missing wallet address format validation

Authorization:

  • ✅ Write operations restricted to Polymarket only
  • ✅ Read-only mode for other exchanges
  • ⚠️ No audit logging for operator trades

Final Assessment

Overall Score: 7.5/10 - Ready with minor fixes

This PR demonstrates architectural maturity and thoughtful security design. The SSE server implementation is production-ready, and the Polymarket package refactoring significantly improves maintainability. The website provides excellent UX for wallet integration.

Key Accomplishments:

  • Successfully enables remote MCP deployment without private key exposure
  • Strong security fundamentals with credential masking and validation
  • Clean architecture enabling future exchange integrations
  • Comprehensive documentation and test coverage

Merge Recommendation: Approve after addressing critical bugs #1 and #2. Item #3 can be tracked as a follow-up issue if time-sensitive.


Generated by Claude Code PR review agent

@railway-app railway-app bot temporarily deployed to dr-manhattan-mcp / staging February 9, 2026 02:36 Inactive
@railway-app railway-app bot temporarily deployed to dr-manhattan-mcp / staging February 9, 2026 02:38 Inactive
@claude
Copy link

claude bot commented Feb 9, 2026

PR Review: Remote MCP Server Implementation

I've completed a thorough review of this PR. Overall, this is excellent work - the implementation is well-structured, secure, and follows best practices. Below are my findings organized by category.


✅ Strengths

Architecture & Design

  • Clean separation of concerns: SSE server, security utilities, operator/builder patterns are well-separated
  • Multiple authentication modes: Operator mode (preferred) and Builder profile provide flexibility
  • Transport-agnostic error messages: Keeps the exchange layer decoupled from HTTP specifics
  • Singleton pattern for ExchangeSessionManager with proper thread-safety
  • Context-based credential injection: Elegant solution for per-request credentials in SSE mode

Security

  • No private keys in SSE mode: Operator and Builder modes avoid storing user private keys on the server
  • Credential masking: sanitize_headers_for_logging() fully redacts sensitive data (no partial exposure)
  • Signature verification: verify_wallet_signature() properly validates wallet ownership with timestamp checks
  • Write operation restrictions: Only Polymarket allowed for write ops, others read-only
  • CORS configuration: Restricted to known origins (claude.ai, console.anthropic.com)
  • Signature expiry: Time-based expiry with configurable durations (24h, 7d, 30d, 90d)
  • Credential zeroization: _zeroize_credentials() clears sensitive data on shutdown

Code Quality

  • Comprehensive test coverage: Tests for credential extraction, masking, validation, write operations
  • Proper timeout handling: _run_with_timeout() prevents hanging operations
  • Environment validation: _validate_env() checks PORT and LOG_LEVEL before startup
  • Excellent documentation: Clear docstrings, inline comments, and wiki guides
  • Logger patching: Clever solution to redirect logs to stderr for MCP compatibility

🔧 Issues Found

1. CRITICAL: Operator Key Security Risk (High Priority)

Location: dr_manhattan/exchanges/polymarket/polymarket_operator.py:70

Issue: The POLYMARKET_OPERATOR_KEY is a server-wide private key that signs orders on behalf of all users. If this key is compromised, an attacker could trade for any user who has approved the operator.

Current Code:

self._operator_key = os.getenv("POLYMARKET_OPERATOR_KEY")

Recommendations:

  1. Key rotation: Implement periodic key rotation with graceful migration
  2. Monitoring: Add logging/alerting for suspicious operator activity (unusual order sizes, frequency)
  3. Rate limiting: Add per-user rate limits to prevent abuse
  4. Documentation: Add clear security warnings in wiki/mcp/remote-server.md about:
    • Server operator must be highly trusted
    • Users should use dedicated wallets with limited funds
    • Operator approval should be revoked when not actively trading
  5. Consider HSM/KMS: For production deployments, store operator key in AWS KMS, Google Cloud KMS, or HashiCorp Vault instead of environment variables

2. Security: CORS Wildcard Risk (Medium Priority)

Location: dr_manhattan/mcp/server_sse.py:287-294

Issue: The default CORS configuration allows https://claude.ai and https://console.anthropic.com, but the code comment mentions "MCP clients typically don't send Origin headers." If clients don't send Origin headers, this CORS config has no effect, potentially allowing any origin.

Current Code:

ALLOWED_ORIGINS: List[str] = [o.strip() for o in _cors_origins_env.split(",") if o.strip()]
if not ALLOWED_ORIGINS:
    ALLOWED_ORIGINS = [
        "https://claude.ai",
        "https://console.anthropic.com",
    ]

Recommendations:

  1. Verify whether MCP clients actually send Origin headers
  2. If they don't, consider removing CORS middleware or using alternative authentication (API keys, rate limiting by IP)
  3. Add a comment explaining the actual CORS behavior with MCP clients

3. Bug: Missing Rate Limiting Implementation (Medium Priority)

Location: dr_manhattan/mcp/server_sse.py:169

Issue: The code calls check_rate_limit() but the implementation in security.py is likely a placeholder. Without proper rate limiting, the server is vulnerable to abuse.

Current Code:

if not check_rate_limit():
    raise ValueError("Rate limit exceeded. Please wait before making more requests.")

Recommendations:

  1. Implement proper rate limiting using:
    • Per-user limits: Based on wallet address (operator mode) or API key (builder mode)
    • Per-IP limits: For anonymous read-only access
    • Per-operation limits: Different limits for read vs write operations
  2. Use a library like slowapi or Redis-based rate limiting
  3. Return proper HTTP 429 status codes (though this is JSON-RPC, so adapt accordingly)

4. Performance: Potential Memory Leak (Low Priority)

Location: dr_manhattan/mcp/session/exchange_manager.py:371-372

Issue: In SSE mode with operator credentials, a new exchange instance is created for each request without caching. For high-traffic deployments, this could cause memory churn.

Current Code:

# Create exchange without caching (each user has different credentials)
return self._create_exchange_with_credentials(exchange_name, exchange_creds)

Recommendations:

  1. For operator mode (same operator key, different user addresses), consider caching with user_address as part of the cache key
  2. Implement LRU cache with size limits to prevent unbounded memory growth
  3. Add periodic cleanup of stale cached instances

5. Code Quality: Inconsistent Error Handling (Low Priority)

Location: Multiple files

Issue: Some functions return tuple[bool, Optional[str]] for errors, while others raise exceptions. This inconsistency makes error handling unpredictable.

Examples:

  • validate_write_operation() → returns tuple
  • create_order() → raises exceptions

Recommendations:

  1. Standardize on one approach (I recommend exceptions for better stack traces)
  2. Or document clearly when each pattern is used (e.g., validation functions return tuples, business logic raises exceptions)

6. Testing: Missing Integration Tests (Medium Priority)

Issue: The tests in test_server_sse.py are mostly unit tests. There are no integration tests that:

  • Actually create an SSE connection
  • Send MCP messages through the full stack
  • Test the operator signature verification end-to-end
  • Test credential rotation scenarios

Recommendations:

  1. Add integration tests using TestClient to hit the /sse and /messages/ endpoints
  2. Mock the Polymarket API responses to test full request flows
  3. Test failure scenarios (expired signatures, invalid credentials, etc.)

7. Documentation: Operator Address Not Exposed (Low Priority)

Location: dr_manhattan/exchanges/polymarket/polymarket_operator.py

Issue: Users need to know the operator address to approve it on-chain, but the operator address isn't clearly exposed through an API endpoint.

Recommendations:

  1. Add a /operator-address endpoint that returns the server's operator address
  2. Update /health endpoint to include operator address
  3. Update documentation to reference this endpoint

📝 Minor Suggestions

  1. Dockerfile optimization (line 14-15): Consider multi-stage build to reduce image size
  2. Environment variables: Move CORS_ALLOWED_ORIGINS to .env.example for better discoverability
  3. Type hints: Add return type hints to handle_sse() and handle_messages()
  4. Website code: The React/TypeScript website code is out of scope for this review, but consider separating it into a different PR for easier review
  5. Logging: Consider structured logging (JSON) for production deployments to enable better log parsing

🎯 Recommendations Summary

Must Fix Before Merge

  1. ✅ Add security warnings to documentation about operator key risks
  2. ✅ Implement proper rate limiting (or add TODO comments if deferring)
  3. ⚠️ Verify CORS behavior with MCP clients and update accordingly

Should Fix Soon

  1. Add integration tests for SSE endpoints
  2. Expose operator address via API endpoint
  3. Implement LRU caching for operator mode exchanges
  4. Consider KMS/HSM for operator key storage

Nice to Have

  1. Standardize error handling patterns
  2. Multi-stage Dockerfile
  3. Structured logging

🏆 Overall Assessment

This PR is production-ready with minor security hardening. The code quality is high, the architecture is sound, and the security model is well-thought-out. The operator pattern is clever and avoids the major security risk of storing user private keys.

Recommendation: Approve with minor changes requested (security warnings + rate limiting clarification).

Great work on this feature! The remote MCP server will significantly improve the user experience for Claude integration.


Review completed using Claude Sonnet 4.5

@claude
Copy link

claude bot commented Feb 9, 2026

PR Review: feat(mcp): add SSE server for remote MCP deployment

Overview

This is a substantial and well-architected PR that adds SSE-based MCP server support for remote deployment, along with a major Polymarket codebase refactoring. The implementation demonstrates strong security practices and thoughtful design decisions.

Overall Assessment: APPROVE with minor suggestions


Strengths

1. Security Implementation

The security utilities in dr_manhattan/mcp/utils/security.py are excellent:

  • Comprehensive credential sanitization: Headers are fully redacted with [REDACTED]
  • Signature-based authentication: Wallet signature verification with timestamp validation
  • Configurable expiry options: 24h, 7d, 30d, 90d with hard maximum of 90 days
  • Clock skew tolerance: 5-minute tolerance for timestamp validation
  • Transport-agnostic error messages
  • Sensitive pattern detection: Regex-based detection of private keys

Security Best Practices Observed:

  • Write operations restricted to Polymarket (Builder profile only)
  • No private keys on server for SSE mode
  • Credentials zeroized on cleanup (exchange_manager.py:169-179)
  • Thread-safe credential operations with locks

2. SSE Server Design

dr_manhattan/mcp/server_sse.py shows careful attention to detail:

  • Logger patching before imports: Critical fix for MCP protocol compliance
  • Context-based credential management: contextvars for per-request credentials
  • Proper CORS configuration: Restricted origins with sensible defaults
  • Graceful shutdown handling: Signal handlers and cleanup routines
  • Environment validation: Port and log level validation before startup

3. Polymarket Refactoring

The monolithic polymarket.py (1930 lines) split into focused modules:

  • Clear separation of concerns: Gamma, CLOB, Data, CTF, WebSocket, Builder, Operator
  • Excellent documentation: polymarket/README.md provides comprehensive API reference
  • Mixin architecture: All methods still accessible on main Polymarket class
  • Stats: 76 methods, 60 public, 16 auth-required

4. Test Coverage

532 lines of new tests across 3 files covering credential extraction, masking, and validation

5. Dockerfile Quality

Clean, production-ready Dockerfile with layer caching, UV usage, health check, and slim base image


Issues & Suggestions

Critical Issues

None found - the implementation is production-ready.

Medium Priority

  1. CORS Configuration: Add explicit documentation about CORS behavior for MCP clients vs web clients
  2. Rate Limiting: Ensure rate limits are documented and configurable for production use
  3. Wiki Documentation: Consider adding wiki/exchanges/polymarket.md per CLAUDE.md Rule 6

Low Priority

  1. Timeout Constants: Consider making EXCHANGE_INIT_TIMEOUT and CLIENT_INIT_TIMEOUT environment-configurable
  2. Credential Zeroization: Consider adding gc.collect() for defense-in-depth

Code Quality

Adherence to CLAUDE.md Rules

  • Rule 1: Clean and focused codebase ✓
  • Rule 2: No unnecessary documentation ✓
  • Rule 3: UV used exclusively ✓
  • Rule 4: Non-sensitive config in code, sensitive in .env ✓
  • Rule 5: Tests exist but should verify they run
  • Rule 6: Should add wiki/exchanges/polymarket.md

Security Assessment

The security implementation is exemplary:

  1. No private keys on remote server for SSE mode
  2. Builder profile API credentials instead of private keys
  3. Signature verification with expiry and replay attack prevention
  4. Credential sanitization in logs
  5. Thread-safe credential operations
  6. Credentials zeroized on cleanup

Recommendations:

  • Ensure HTTPS enforcement at deployment level
  • Consider audit logging for write operations

Test Coverage

Positive: 532 lines of new tests, security functions well-tested

Gaps: Add tests for:

  1. Expired signature rejection
  2. Future timestamp rejection
  3. Signature from wrong wallet
  4. Timeout scenarios

Summary

This PR represents high-quality work with excellent security practices and thoughtful architecture.

Recommendations Before Merge

  1. Run full test suite (per CLAUDE.md Rule 5)
  2. Add wiki/exchanges/polymarket.md (per CLAUDE.md Rule 6)
  3. Document rate limiting behavior
  4. Verify HTTPS enforcement at deployment level

Post-Merge Enhancements (Optional)

  1. Add integration tests for SSE server
  2. Add structured logging for production
  3. Consider metrics endpoint for observability

Verdict: LGTM with minor follow-up suggestions

Great work on this implementation! The security-first approach and clean architecture are commendable.

@guzus guzus merged commit b130a50 into main Feb 9, 2026
16 checks passed
@claude
Copy link

claude bot commented Feb 9, 2026

Pull Request Review: SSE-based MCP Server for Remote Deployment

Summary

This PR adds significant infrastructure for remote MCP deployment via Server-Sent Events (SSE), containerization, and a web-based authentication flow. The implementation is well-thought-out with strong security considerations.


✅ Strengths

Architecture & Design

  1. Clean SSE Implementation: The server_sse.py follows MCP protocol properly with context-based credential management
  2. Security-First Approach: Operator mode with signature verification prevents private key exposure. Sensitive headers fully redacted in logs (no partial exposure). Write operations restricted to Polymarket only via Builder profile. Signature expiry validation with reasonable limits (24h-90d).
  3. Polymarket Refactoring: Breaking the monolithic polymarket.py into focused modules (polymarket_core.py, polymarket_clob.py, etc.) greatly improves maintainability
  4. Good Test Coverage: test_server_sse.py covers critical security paths (credential extraction, masking, validation, write restrictions)
  5. CLAUDE.md Compliance: Follows project rules (UV for deps, minimal .env vars, proactive debugging)

Code Quality

  • Thread-safe credential handling with proper locks
  • Context variables for per-request credentials
  • Comprehensive error translation for MCP protocol
  • Rate limiting with token bucket algorithm (10 calls/sec, burst of 20)

@claude
Copy link

claude bot commented Feb 9, 2026

🔴 Critical Issues

1. SECURITY: .env.example Violates CLAUDE.md Rule #4

File: .env.example:5-9

Issue: CLAUDE.md explicitly states "DO NOT place many variables in .env file. Place them in the code instead." These Builder API credentials are being added to .env when they should follow the pattern in exchange_manager.py where non-sensitive config uses code defaults.

Recommendation: If these are truly sensitive (API keys), this is acceptable. However, if they're just configuration, they should use code defaults with optional env override like POLYMARKET_SIGNATURE_TYPE does.

2. SECURITY: Operator Mode - Missing Server Private Key Validation

File: dr_manhattan/mcp/session/exchange_manager.py:256-277

The operator mode implementation checks for user_address but doesn't validate that the server's private key is configured. The server needs its own private key to sign orders on behalf of users in operator mode. If POLYMARKET_PRIVATE_KEY is not set in the server environment, this will fail at runtime when trying to place orders.

Recommendation: Add validation before creating PolymarketOperator instance to ensure server private key exists.

3. SECURITY: Railway Public Deployment Concerns

Context: PR description mentions Railway deployment at production URL

Issues:
a) No Authentication: The SSE endpoint has no authentication mechanism beyond optional headers. Anyone can connect and read market data. While read operations are safe, this could lead to DoS via rate limit exhaustion and cost abuse.

b) Operator Mode Risk: If the server's private key has significant funds, a malicious user could drain it by sending valid signatures for their own wallet and having the server sign malicious transactions.

Recommendations:

  • Add API key authentication for the Railway endpoint
  • Rate limit per IP, not just globally
  • Use a dedicated wallet with minimal funds for operator mode
  • Document the security model clearly in wiki/mcp/remote-server.md

@claude
Copy link

claude bot commented Feb 9, 2026

⚠️ Major Issues

4. Rate Limiting Per-User Not Implemented

File: dr_manhattan/mcp/utils/rate_limiter.py

The rate limiter is global across all users. In SSE mode with multiple users, one user can exhaust the rate limit for everyone. This is a poor user experience and potential DoS vector.

Recommendation: Implement per-user rate limiting using wallet address or session ID as the key.

5. Dockerfile Security & Efficiency

File: Dockerfile:15

Issues:
a) Installing as root (no USER directive)
b) pyproject.toml is copied but uv.lock is not, leading to non-reproducible builds

Recommendations: Create non-root user, copy uv.lock for reproducible builds, run as non-root.

6. Credentials Not Zeroized on Failed Cleanup

File: dr_manhattan/mcp/session/exchange_manager.py:484-491

Issue: If client cleanup fails, credentials are not zeroized because the code only calls _zeroize_credentials() after successful cleanup. This leaves sensitive data in memory.

Recommendation: Always zeroize, even on partial failure using finally block.

@claude
Copy link

claude bot commented Feb 9, 2026

💡 Suggestions & Minor Issues

7. Magic Numbers in Security Module

File: dr_manhattan/mcp/utils/security.py:303

Use named constants instead of magic number 300 for clock skew tolerance.

8. Missing Error Context in SSE Handler

File: dr_manhattan/mcp/server_sse.py:186-189

Errors are caught but original exception context is lost. Log the full traceback with logger.exception() for debugging.

9. Website Config Hardcoded URL

File: website/src/pages/ApprovePage.tsx:92

Hardcoded production URL makes it hard for users to test against local/staging instances. Make this configurable via environment variable at build time.

10. Missing CORS Preflight Test

The SSE server allows OPTIONS method but there are no tests for CORS preflight requests. Given the security implications, this should be tested.

@claude
Copy link

claude bot commented Feb 9, 2026

📊 Statistics & Final Verdict

Files Changed: 62 (manageable for a feature PR)
Lines Added: 11,725
Lines Deleted: 4,053
Net Change: +7,672 (significant but justified by new features)

Code Distribution:

  • Core SSE server: ~400 lines
  • Security utilities: ~350 lines
  • Tests: ~370 lines (good coverage)
  • Polymarket refactor: ~5,000 lines (module split, no new logic)
  • Website: ~3,000 lines (React app)

🎯 Recommendations

Must Fix (Before Merge)

  1. Fix operator mode server private key validation (add logo #2)
  2. Implement per-user rate limiting (fix: polymarket impl #4)
  3. Fix credentials zeroization on failed cleanup (Better MX #6)
  4. Add non-root user to Dockerfile (Create debugging frontend for trading strategies #5)

Should Fix (Before Production)

  1. Add API key authentication for Railway endpoint (#3a)
  2. Implement per-IP rate limiting (#3a)
  3. Document operator mode security model (#3c)
  4. Add CORS preflight tests (refactor: simplify release workflow by removing TestPyPI publishing step #10)

Nice to Have

  1. Make website MCP URL configurable (Add CI & black #9)
  2. Add error logging with full context (Add vpin strategies #8)
  3. Extract magic numbers to constants (Add Claude Code GitHub Workflow #7)

✨ Final Verdict

This is a well-designed PR with strong security awareness. The code quality is high, tests are comprehensive, and the architecture is solid. However, the critical security issues (#2, #3) must be addressed before merging, especially for a public-facing deployment.

The Polymarket refactoring is a huge win for maintainability, and the SSE implementation follows best practices. Once the security concerns are addressed, this will be a great addition to the project.

Recommendation: Request changes for critical issues, then approve.


📚 Additional Notes

  • The website integration is polished (ConnectButton, signature flow, copy-paste config)
  • Good use of TypeScript in frontend
  • Comprehensive documentation in wiki/mcp/remote-server.md
  • Rate limiter token bucket implementation is textbook-correct

Great work overall! 🚀

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.

Deploy MCP Server (Read only)

3 participants