-
-
Notifications
You must be signed in to change notification settings - Fork 133
Prompt/add cite component #159
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
9588e8c
release v1.0.0 for `general`
ChengJiale150 f5c15b0
add `jupyter-cite`
ChengJiale150 6e1c083
add docs for prompt section
ChengJiale150 6cc0344
bump to 0.19.0
ChengJiale150 1e5ead7
update docs
ChengJiale150 1aed8a7
better docs
ChengJiale150 8393eaa
Update docs/docs/prompts/index.mdx
ChengJiale150 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,2 @@ | ||
| label: "Clients" | ||
| position: 6 | ||
| position: 7 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| label: "Prompts" | ||
| position: 6 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| # Prompts | ||
|
|
||
| The server currently offers 1 prompt for user. | ||
|
|
||
| :::warning | ||
|
|
||
| Not all MCP Clients support the Prompt Feature. You need to ensure that your MCP Client supports it to enable this feature. | ||
| Current known MCP Client support status for Prompt: | ||
| - Supported: `Claude desktop`, [`Claude Code`](https://docs.claude.com/en/docs/claude-code/mcp#execute-mcp-prompts), [`Gemini CLI`](https://geminicli.com/docs/tools/mcp-server/#invoking-prompts) | ||
| - Not supported: `Cursor` | ||
|
|
||
| ::: | ||
|
|
||
| ## Jupyter Core Prompt (1 prompt) | ||
|
|
||
| This is the core Prompt component of Jupyter MCP, providing universal and powerful Prompt tools, all prefixed with `jupyter`. | ||
|
|
||
| ### 1. `jupyter-cite` | ||
|
|
||
| This prompt allows users to cite specific cells in a notebook, enabling users to let LLM perform precise subsequent operations on specific cells. | ||
|
|
||
| #### Input Parameters | ||
|
|
||
| - `--prompt`: User prompt for the cited cells | ||
| - `--cell_indices`: Cell indices to cite (0-based), supporting flexible range format | ||
| 1. **Single Index**: Cite a single cell, such as `"0"` (cites the 1st cell) | ||
| 2. **Range Format**: Cite a continuous range of cells, such as `"0-2"` (cites cells 1 to 3) | ||
| 3. **Mixed Format**: Combine single index and range, such as `"0-2,4"` (cites cells 1-3 and cell 5) | ||
| 4. **Open-ended Range**: From specified index to the end of notebook, such as `"3-"` (cites from cell 4 to the last cell) | ||
| - `--notebook_path`: Name of the notebook to cite cells from, default ("") to current activated notebook | ||
|
|
||
| #### Output Format | ||
|
|
||
| ``` | ||
| USER Cite cells {cell_indices} from notebook {notebook_name}, here are the cells: | ||
| =====Cell {cell_index} | type: {cell_type} | execution count: {execution_count}===== | ||
| {cell_source} | ||
| ...(other cells) | ||
| =====End of Cited Cells===== | ||
| USER's Instruction are follow: {prompt} | ||
| ``` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,4 +4,4 @@ | |
|
|
||
| """Jupyter MCP Server.""" | ||
|
|
||
| __version__ = "0.18.2" | ||
| __version__ = "0.19.0" | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,171 @@ | ||
| # Copyright (c) 2023-2024 Datalayer, Inc. | ||
| # | ||
| # BSD 3-Clause License | ||
|
|
||
| """cite from a notebook.""" | ||
|
|
||
| from typing import Any, Optional | ||
| from mcp.server.fastmcp.prompts.base import UserMessage | ||
| from jupyter_server_client import JupyterServerClient | ||
| from jupyter_mcp_server.tools._base import BaseTool, ServerMode | ||
| from jupyter_mcp_server.notebook_manager import NotebookManager | ||
| from jupyter_mcp_server.models import Notebook | ||
|
|
||
|
|
||
| class JupyterCitePrompt(BaseTool): | ||
| """Tool to cite specific cells from specified notebook.""" | ||
|
|
||
| def _parse_cell_indices(self, cell_indices_str: str, max_cells: int) -> list[int]: | ||
| """ | ||
| Parse cell indices from a string with flexible format. | ||
|
|
||
| Supports formats like: | ||
| - '0,1,2' for individual indices | ||
| - '0-2' for ranges | ||
| - '0-2,4' for mixed format | ||
| - '3-' for from index 3 to end | ||
|
|
||
| Args: | ||
| cell_indices_str: String with cell indices | ||
| max_cells: Maximum number of cells in the notebook | ||
|
|
||
| Returns: | ||
| List of integer cell indices | ||
|
|
||
| Raises: | ||
| ValueError: If indices are invalid or out of range | ||
| """ | ||
| if not cell_indices_str or not cell_indices_str.strip(): | ||
| raise ValueError("Cell indices cannot be empty") | ||
|
|
||
| # Check if notebook is empty | ||
| if max_cells <= 0: | ||
| raise ValueError("Notebook has no cells") | ||
|
|
||
| result = set() | ||
| parts = cell_indices_str.split(',') | ||
|
|
||
| for part in parts: | ||
| part = part.strip() | ||
| if not part: | ||
| continue | ||
|
|
||
| if '-' in part: | ||
| # Handle range format | ||
| range_parts = part.split('-', 1) | ||
|
|
||
| if len(range_parts) == 2: | ||
| start_str, end_str = range_parts | ||
|
|
||
| if not start_str: | ||
| raise ValueError(f"Invalid range format: {part}") | ||
|
|
||
| try: | ||
| start = int(start_str) | ||
| except ValueError: | ||
| raise ValueError(f"Invalid start index: {start_str}") | ||
|
|
||
| if start < 0: | ||
| raise ValueError(f"Start index cannot be negative: {start}") | ||
|
|
||
| if not end_str: | ||
| # Case: '3-' means from 3 to end | ||
| end = max_cells - 1 | ||
| # Check if start is within range | ||
| if start >= max_cells: | ||
| raise ValueError(f"Cell index {start} is out of range. Notebook has {max_cells} cells.") | ||
| else: | ||
| try: | ||
| end = int(end_str) | ||
| except ValueError: | ||
| raise ValueError(f"Invalid end index: {end_str}") | ||
|
|
||
| if end < start: | ||
| raise ValueError(f"End index ({end}) must be greater than or equal to start index ({start})") | ||
| else: | ||
| raise ValueError(f"Invalid range format: {part}") | ||
|
|
||
| # Add all indices in the range | ||
| for i in range(start, end + 1): | ||
| if i >= max_cells: | ||
| raise ValueError(f"Cell index {i} is out of range. Notebook has {max_cells} cells.") | ||
| result.add(i) | ||
| else: | ||
| # Handle single index | ||
| try: | ||
| index = int(part) | ||
| except ValueError: | ||
| raise ValueError(f"Invalid cell index: {part}") | ||
|
|
||
| if index < 0: | ||
| raise ValueError(f"Cell index cannot be negative: {index}") | ||
| if index >= max_cells: | ||
| raise ValueError(f"Cell index {index} is out of range. Notebook has {max_cells} cells.") | ||
|
|
||
| result.add(index) | ||
|
|
||
| # Convert to sorted list | ||
| return sorted(result) | ||
|
|
||
| async def execute( | ||
| self, | ||
| mode: ServerMode, | ||
| server_client: Optional[JupyterServerClient] = None, | ||
| contents_manager: Optional[Any] = None, | ||
| notebook_manager: Optional[NotebookManager] = None, | ||
| cell_indices: Optional[str] = None, | ||
| notebook_name: Optional[str] = None, | ||
| prompt: Optional[str] = None, | ||
| **kwargs | ||
| ) -> str: | ||
| """Execute the read_notebook tool. | ||
|
|
||
| Args: | ||
| mode: Server mode (MCP_SERVER or JUPYTER_SERVER) | ||
| contents_manager: Direct API access for JUPYTER_SERVER mode | ||
| notebook_manager: Notebook manager instance | ||
| notebook_name: Notebook identifier to read | ||
| response_format: Response format (brief or detailed) | ||
| start_index: Starting index for pagination (0-based) | ||
| limit: Maximum number of items to return (0 means no limit) | ||
| **kwargs: Additional parameters | ||
|
|
||
| Returns: | ||
| Formatted table with cell information | ||
| """ | ||
| if notebook_name == "": | ||
| notebook_name = notebook_manager._current_notebook | ||
| if notebook_name not in notebook_manager: | ||
| raise ValueError(f"Notebook '{notebook_name}' is not connected. All currently connected notebooks: {list(notebook_manager.list_all_notebooks().keys())}") | ||
|
|
||
| if mode == ServerMode.JUPYTER_SERVER and contents_manager is not None: | ||
| # Local mode: read notebook directly from file system | ||
| notebook_path = notebook_manager.get_notebook_path(notebook_name) | ||
|
|
||
| model = await contents_manager.get(notebook_path, content=True, type='notebook') | ||
| if 'content' not in model: | ||
| raise ValueError(f"Could not read notebook content from {notebook_path}") | ||
| notebook = Notebook(**model['content']) | ||
| elif mode == ServerMode.MCP_SERVER and notebook_manager is not None: | ||
| # Remote mode: use WebSocket connection to Y.js document | ||
| async with notebook_manager.get_notebook_connection(notebook_name) as notebook_content: | ||
| notebook = Notebook(**notebook_content.as_dict()) | ||
| else: | ||
| raise ValueError(f"Invalid mode or missing required clients: mode={mode}") | ||
|
|
||
| # Parse cell indices with flexible format | ||
| parsed_indices = self._parse_cell_indices(cell_indices, len(notebook)) | ||
|
|
||
| prompt_list = [f"USER Cite cells {parsed_indices} from notebook {notebook_name}, here are the cells:"] | ||
| for cell_index in parsed_indices: | ||
| cell = notebook.cells[cell_index] | ||
| prompt_list.append(f"=====Cell {cell_index} | type: {cell.cell_type} | execution count: {cell.execution_count if cell.execution_count else 'N/A'}=====") | ||
| prompt_list.append(cell.get_source('readable')) | ||
|
|
||
| prompt_list.append("=====End of Cited Cells=====") | ||
| prompt_list.append(f"USER's Instruction are follow: {prompt}") | ||
|
|
||
| return [UserMessage(content="\n".join(prompt_list))] | ||
|
|
||
|
|
||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.