jupyter_mcp_server
MCP<!-- ~ Copyright (c) 2024- Datalayer, Inc. ~ ~ BSD 3-Clause License -->
Dimension scores
Compatibility
| Framework | Status | Notes |
|---|---|---|
| Claude Code | ✓ | Requires stdio transport configuration via args/env vars, Auto-enrollment of notebooks may need careful client configuration |
| OpenAI Agents SDK | ~ | SSE transport supported but requires HTTP setup, Complex nested tool schemas may need flattening for OpenAI format, Jupyter-specific types (kernel_id, cell_indices) may not translate cleanly, Async execution model may conflict with OpenAI's sync function calling |
| LangChain | ~ | Stateful notebook management conflicts with LangChain's stateless tool model, Current notebook context tracking may not serialize well, YDoc collaborative editing state won't work with LangChain's execution model, Would need custom wrapper to handle notebook_manager and server_context |
Security findings
Command injection via unsanitized notebook_path in subprocess execution
In tests/conftest.py:93-102, notebook paths from user input are passed directly to subprocess commands without validation. The _start_server function executes commands like ['jupyter', 'lab', '--ServerApp.root_dir', './dev/content'] where paths could contain shell metacharacters.
Path traversal vulnerability in notebook path handling
In jupyter_mcp_server/enroll.py:56-57, config.document_id is used directly as a file path without sanitization: 'path=config.document_id'. No validation against '../' patterns or absolute path restrictions. Similar issue in server_context.py where paths are used without validation.
Hardcoded authentication token in test configuration
In tests/conftest.py:30, JUPYTER_TOKEN = 'MY_TOKEN' is hardcoded and used throughout tests. In tests/test_jupyter_extension.py:46, this token is passed in Authorization headers, demonstrating the authentication mechanism uses weak static credentials.
Insufficient input validation on tool parameters
In tests/test_prompts.py:33-38, cell_indices parameter accepts arbitrary strings like '0-2,4' without validation before processing. The jupyter_cite function could be exploited with malformed indices to cause errors or access unintended cells.
No validation of runtime_url configuration
In jupyter_mcp_server/server_context.py:62-72, runtime_url is validated only for None/empty values but not for SSRF protection. An attacker could provide 'http://169.254.169.254/latest/meta-data/' or other internal URLs to probe internal infrastructure.
Verbose error messages expose internal state
In jupyter_mcp_server/server_context.py:67-73, error messages reveal detailed internal configuration: 'runtime_url is not configured (current value: {repr(runtime_url)}). Please check: 1. RUNTIME_URL environment variable...' This leaks environment variable names and system architecture.
Missing length limits on string inputs
Credentials logged in error handling
Weak timeout configuration allows resource exhaustion
Reliability
Success rate
55%
Calls made
100
Avg latency
800ms
P95 latency
2000ms
Failure modes
- • Config initialization failures when runtime_url is 'None' string or empty - ValueError with detailed message but server may crash
- • Subprocess startup failures when ports are in use - pytest.fail() called which halts test execution rather than graceful degradation
- • Process cleanup hangs when terminate() times out - kill() used but process may still be stuck according to logs
- • HTTP client operations lack comprehensive timeout handling - only some requests have timeout=10, others may hang indefinitely
- • Cache operations may fail silently - returns empty list on error without re-raising, masking underlying issues
- • ServerContext singleton initialization can raise ValueError but no try/catch at call sites in main server startup
- • Auto-enrollment failures are logged as warnings but don't prevent server start - may lead to confusing state where server runs but default notebook unavailable
- • Tool cache uses asyncio.Lock but no timeout on lock acquisition - potential deadlock if lock holder crashes
- • Subprocess stdout/stderr redirected to DEVNULL - debugging startup failures becomes difficult as all output is suppressed
- • No validation that kernel_id exists before attempting to connect - will fail at execution time with unclear error
- • Missing error handling for notebook manager operations - add_notebook/set_current_notebook can fail but not caught in auto_enroll
- • Resource cleanup in _start_server may fail if process.wait() hangs - no hard kill timeout
Code health
License
BSD-3-Clause
Has tests
Yes
Has CI
Yes
Dependencies
unknown
This is a Jupyter MCP server implementation with moderate code health. Strengths: BSD 3-Clause license, comprehensive README (15KB), active documentation site with Docusaurus, test suite present (pytest with fixtures), pre-commit hooks configured, Docker support, and clear architecture documentation (22KB ARCHITECTURE.md). The project has good development practices with CONTRIBUTING.md, CODE_OF_CONDUCT.md, and RELEASE.md files. Testing infrastructure includes conftest.py with session fixtures, test mode configuration, and timeout wrappers. CI appears configured via .pre-commit-config.yaml. Weaknesses: No visible CHANGELOG, no explicit type checking (TypeScript/mypy config not found in provided files), cannot verify Git activity metrics, dependency health, or PyPI publication status from static analysis alone. The codebase shows professional structure with proper licensing headers, modular design (separate extension/server modes), and comprehensive documentation. Missing coverage reports and explicit version management in git would improve transparency.