Skip to content

Commit 3f88f66

Browse files
Feat/add JUPYTER_URL and JUPYTER_TOKEN (#125)
* add `JUPYTER_URL` and `JUPYTER_TOKEN` * update README and version
1 parent f9c33ad commit 3f88f66

File tree

3 files changed

+113
-39
lines changed

3 files changed

+113
-39
lines changed

README.md

Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -142,11 +142,8 @@ Then, configure your client:
142142
"command": "uvx",
143143
"args": ["jupyter-mcp-server@latest"],
144144
"env": {
145-
"DOCUMENT_URL": "http://localhost:8888",
146-
"DOCUMENT_TOKEN": "MY_TOKEN",
147-
"DOCUMENT_ID": "notebook.ipynb",
148-
"RUNTIME_URL": "http://localhost:8888",
149-
"RUNTIME_TOKEN": "MY_TOKEN",
145+
"JUPYTER_URL": "http://localhost:8888",
146+
"JUPYTER_TOKEN": "MY_TOKEN",
150147
"ALLOW_IMG_OUTPUT": "true"
151148
}
152149
}
@@ -167,20 +164,14 @@ Then, configure your client:
167164
"command": "docker",
168165
"args": [
169166
"run", "-i", "--rm",
170-
"-e", "DOCUMENT_URL",
171-
"-e", "DOCUMENT_TOKEN",
172-
"-e", "DOCUMENT_ID",
173-
"-e", "RUNTIME_URL",
174-
"-e", "RUNTIME_TOKEN",
167+
"-e", "JUPYTER_URL",
168+
"-e", "JUPYTER_TOKEN",
175169
"-e", "ALLOW_IMG_OUTPUT",
176170
"datalayer/jupyter-mcp-server:latest"
177171
],
178172
"env": {
179-
"DOCUMENT_URL": "http://host.docker.internal:8888",
180-
"DOCUMENT_TOKEN": "MY_TOKEN",
181-
"DOCUMENT_ID": "notebook.ipynb",
182-
"RUNTIME_URL": "http://host.docker.internal:8888",
183-
"RUNTIME_TOKEN": "MY_TOKEN",
173+
"JUPYTER_URL": "http://host.docker.internal:8888",
174+
"JUPYTER_TOKEN": "MY_TOKEN",
184175
"ALLOW_IMG_OUTPUT": "true"
185176
}
186177
}
@@ -196,21 +187,15 @@ Then, configure your client:
196187
"command": "docker",
197188
"args": [
198189
"run", "-i", "--rm",
199-
"-e", "DOCUMENT_URL",
200-
"-e", "DOCUMENT_TOKEN",
201-
"-e", "DOCUMENT_ID",
202-
"-e", "RUNTIME_URL",
203-
"-e", "RUNTIME_TOKEN",
190+
"-e", "JUPYTER_URL",
191+
"-e", "JUPYTER_TOKEN",
204192
"-e", "ALLOW_IMG_OUTPUT",
205193
"--network=host",
206194
"datalayer/jupyter-mcp-server:latest"
207195
],
208196
"env": {
209-
"DOCUMENT_URL": "http://localhost:8888",
210-
"DOCUMENT_TOKEN": "MY_TOKEN",
211-
"DOCUMENT_ID": "notebook.ipynb",
212-
"RUNTIME_URL": "http://localhost:8888",
213-
"RUNTIME_TOKEN": "MY_TOKEN",
197+
"JUPYTER_URL": "http://localhost:8888",
198+
"JUPYTER_TOKEN": "MY_TOKEN",
214199
"ALLOW_IMG_OUTPUT": "true"
215200
}
216201
}
@@ -221,9 +206,10 @@ Then, configure your client:
221206
</details>
222207

223208
> [!TIP]
224-
> 1. Ensure the `port` of the `DOCUMENT_URL` and `RUNTIME_URL` match those used in the `jupyter lab` command.
225-
> 2. In a basic setup, `DOCUMENT_URL` and `RUNTIME_URL` are the same. `DOCUMENT_TOKEN`, and `RUNTIME_TOKEN` are also the same and is actually the Jupyter Token.
226-
> 3. The `DOCUMENT_ID` parameter specifies the path to the notebook you want to connect to. It should be relative to the directory where JupyterLab was started.
209+
> 1. **Port Configuration**: Ensure the `port` in your Jupyter URLs matches the one used in the `jupyter lab` command. For simplified config, set this in `JUPYTER_URL`.
210+
> 2. **Server Separation**: The different URL and token variables exist because some deployments separate notebook storage (`DOCUMENT_*`) from kernel execution (`RUNTIME_*`). Use `JUPYTER_URL` and `JUPYTER_TOKEN` when both services are on the same server, or set individual variables for advanced deployments.
211+
> 3. **Authentication**: In most cases, document and runtime services use the same authentication token. Use `JUPYTER_TOKEN` for simplified config or set `DOCUMENT_TOKEN` and `RUNTIME_TOKEN` individually for different credentials.
212+
> 4. **Notebook Path**: The `DOCUMENT_ID` parameter specifies the path to the notebook you want to connect to. It should be relative to the directory where JupyterLab was started.
227213
> - **Optional:** If you omit `DOCUMENT_ID`, the MCP client can automatically list all available notebooks on the Jupyter server, allowing you to select one interactively via your prompts.
228214
> - **Flexible:** Even if you set `DOCUMENT_ID`, the MCP client can still browse, list, switch to, or even create new notebooks at any time.
229215

jupyter_mcp_server/CLI.py

Lines changed: 98 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def _common_options(f):
3838
"--runtime-url",
3939
envvar="RUNTIME_URL",
4040
type=click.STRING,
41-
default="http://localhost:8888",
41+
default=None,
4242
help="The runtime URL to use. For the jupyter provider, this is the Jupyter server URL. For the datalayer provider, this is the Datalayer runtime URL.",
4343
),
4444
click.option(
@@ -59,7 +59,7 @@ def _common_options(f):
5959
"--document-url",
6060
envvar="DOCUMENT_URL",
6161
type=click.STRING,
62-
default="http://localhost:8888",
62+
default=None,
6363
help="The document URL to use. For the jupyter provider, this is the Jupyter server URL. For the datalayer provider, this is the Datalayer document URL.",
6464
),
6565
click.option(
@@ -75,13 +75,77 @@ def _common_options(f):
7575
type=click.STRING,
7676
default=None,
7777
help="The document token to use for authentication with the provider. If not provided, the provider should accept anonymous requests.",
78+
),
79+
click.option(
80+
"--jupyter-url",
81+
envvar="JUPYTER_URL",
82+
type=click.STRING,
83+
default=None,
84+
help="The Jupyter URL to use as default for both document and runtime URLs. If not provided, individual URL settings take precedence.",
85+
),
86+
click.option(
87+
"--jupyter-token",
88+
envvar="JUPYTER_TOKEN",
89+
type=click.STRING,
90+
default=None,
91+
help="The Jupyter token to use as default for both document and runtime tokens. If not provided, individual token settings take precedence.",
7892
)
7993
]
8094
# Apply decorators in reverse order
8195
for option in reversed(options):
8296
f = option(f)
8397
return f
8498

99+
100+
def _resolve_url_and_token_variables(
101+
jupyter_url, jupyter_token,
102+
document_url, document_token,
103+
runtime_url, runtime_token,
104+
) -> tuple[str, str | None, str, str | None]:
105+
"""Resolve URL and token variables based on priority logic.
106+
107+
Priority order:
108+
1. Individual URL/token variables take precedence if set
109+
2. JUPYTER_URL/JUPYTER_TOKEN used as fallback if individual variables are None
110+
3. Keep original default values if neither individual nor merged variables are set
111+
112+
Args:
113+
jupyter_url: The merged Jupyter URL variable
114+
jupyter_token: The merged Jupyter token variable
115+
document_url: The individual document URL (takes precedence if set)
116+
document_token: The individual document token (takes precedence if set)
117+
runtime_url: The individual runtime URL (takes precedence if set)
118+
runtime_token: The individual runtime token (takes precedence if set)
119+
120+
Returns:
121+
Tuple of (resolved_document_url, resolved_document_token, resolved_runtime_url, resolved_runtime_token)
122+
"""
123+
124+
# Resolve document_url
125+
if document_url is not None:
126+
resolved_document_url = document_url
127+
elif jupyter_url is not None:
128+
resolved_document_url = jupyter_url
129+
else:
130+
resolved_document_url = "http://localhost:8888"
131+
132+
# Resolve runtime_url
133+
if runtime_url is not None:
134+
resolved_runtime_url = runtime_url
135+
elif jupyter_url is not None:
136+
resolved_runtime_url = jupyter_url
137+
else:
138+
resolved_runtime_url = "http://localhost:8888"
139+
140+
# Resolve document_token
141+
resolved_document_token = document_token or jupyter_token
142+
143+
# Resolve runtime_token
144+
resolved_runtime_token = runtime_token or jupyter_token
145+
146+
return resolved_document_url, resolved_document_token, resolved_runtime_url, resolved_runtime_token
147+
148+
85149
def _do_start(
86150
transport: str,
87151
start_new_runtime: bool,
@@ -191,6 +255,8 @@ def server(
191255
document_url: str,
192256
document_id: str,
193257
document_token: str,
258+
jupyter_url: str,
259+
jupyter_token: str,
194260
port: int,
195261
provider: str,
196262
):
@@ -206,15 +272,25 @@ def server(
206272
return
207273

208274
# No subcommand provided - execute the default start behavior
275+
# Resolve URL and token variables based on priority logic
276+
resolved_document_url, resolved_document_token, resolved_runtime_url, resolved_runtime_token = _resolve_url_and_token_variables(
277+
jupyter_url=jupyter_url,
278+
jupyter_token=jupyter_token,
279+
document_url=document_url,
280+
document_token=document_token,
281+
runtime_url=runtime_url,
282+
runtime_token=runtime_token,
283+
)
284+
209285
_do_start(
210286
transport=transport,
211287
start_new_runtime=start_new_runtime,
212-
runtime_url=runtime_url,
288+
runtime_url=resolved_runtime_url,
213289
runtime_id=runtime_id,
214-
runtime_token=runtime_token,
215-
document_url=document_url,
290+
runtime_token=resolved_runtime_token,
291+
document_url=resolved_document_url,
216292
document_id=document_id,
217-
document_token=document_token,
293+
document_token=resolved_document_token,
218294
port=port,
219295
provider=provider,
220296
)
@@ -322,19 +398,31 @@ def start_command(
322398
document_url: str,
323399
document_id: str,
324400
document_token: str,
401+
jupyter_url: str,
402+
jupyter_token: str,
325403
port: int,
326404
provider: str,
327405
):
328406
"""Start the Jupyter MCP server with a transport."""
407+
# Resolve URL and token variables based on priority logic
408+
resolved_document_url, resolved_document_token, resolved_runtime_url, resolved_runtime_token = _resolve_url_and_token_variables(
409+
jupyter_url=jupyter_url,
410+
jupyter_token=jupyter_token,
411+
document_url=document_url,
412+
document_token=document_token,
413+
runtime_url=runtime_url,
414+
runtime_token=runtime_token,
415+
)
416+
329417
_do_start(
330418
transport=transport,
331419
start_new_runtime=start_new_runtime,
332-
runtime_url=runtime_url,
420+
runtime_url=resolved_runtime_url,
333421
runtime_id=runtime_id,
334-
runtime_token=runtime_token,
335-
document_url=document_url,
422+
runtime_token=resolved_runtime_token,
423+
document_url=resolved_document_url,
336424
document_id=document_id,
337-
document_token=document_token,
425+
document_token=resolved_document_token,
338426
port=port,
339427
provider=provider,
340428
)

jupyter_mcp_server/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44

55
"""Jupyter MCP Server."""
66

7-
__version__ = "0.16.2"
7+
__version__ = "0.16.3"

0 commit comments

Comments
 (0)