clikernel 0.2.6__tar.gz → 0.2.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {clikernel-0.2.6 → clikernel-0.2.7}/CHANGELOG.md +9 -0
- {clikernel-0.2.6/clikernel.egg-info → clikernel-0.2.7}/PKG-INFO +8 -4
- {clikernel-0.2.6 → clikernel-0.2.7}/README.md +5 -1
- {clikernel-0.2.6 → clikernel-0.2.7}/clikernel/__init__.py +1 -1
- {clikernel-0.2.6 → clikernel-0.2.7}/clikernel/_modidx.py +3 -0
- {clikernel-0.2.6 → clikernel-0.2.7}/clikernel/core.py +24 -8
- {clikernel-0.2.6 → clikernel-0.2.7}/clikernel/mcp.py +28 -9
- {clikernel-0.2.6 → clikernel-0.2.7}/clikernel/stream.py +5 -1
- {clikernel-0.2.6 → clikernel-0.2.7/clikernel.egg-info}/PKG-INFO +8 -4
- {clikernel-0.2.6 → clikernel-0.2.7}/clikernel.egg-info/requires.txt +2 -2
- {clikernel-0.2.6 → clikernel-0.2.7}/pyproject.toml +2 -2
- {clikernel-0.2.6 → clikernel-0.2.7}/LICENSE +0 -0
- {clikernel-0.2.6 → clikernel-0.2.7}/MANIFEST.in +0 -0
- {clikernel-0.2.6 → clikernel-0.2.7}/clikernel/cli.py +0 -0
- {clikernel-0.2.6 → clikernel-0.2.7}/clikernel/skill.py +0 -0
- {clikernel-0.2.6 → clikernel-0.2.7}/clikernel.egg-info/SOURCES.txt +0 -0
- {clikernel-0.2.6 → clikernel-0.2.7}/clikernel.egg-info/dependency_links.txt +0 -0
- {clikernel-0.2.6 → clikernel-0.2.7}/clikernel.egg-info/entry_points.txt +0 -0
- {clikernel-0.2.6 → clikernel-0.2.7}/clikernel.egg-info/top_level.txt +0 -0
- {clikernel-0.2.6 → clikernel-0.2.7}/setup.cfg +0 -0
- {clikernel-0.2.6 → clikernel-0.2.7}/tests/test_stream.py +0 -0
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- do not remove -->
|
|
4
4
|
|
|
5
|
+
## 0.2.7
|
|
6
|
+
|
|
7
|
+
### New Features
|
|
8
|
+
|
|
9
|
+
- Add stdin support via MCP elicitation, kernel env propagation, and Client async context manager for scoped kernel lifecycle ([#45](https://github.com/AnswerDotAI/clikernel/issues/45))
|
|
10
|
+
- Simplify MCP tool docstrings by using literal docstrings with conditional suffixes for non-quiet mode instead of f-string assignment ([#44](https://github.com/AnswerDotAI/clikernel/issues/44))
|
|
11
|
+
- Add --quiet option to suppress kernel startup output from connect, restart, and auto-connect execute replies ([#43](https://github.com/AnswerDotAI/clikernel/issues/43))
|
|
12
|
+
|
|
13
|
+
|
|
5
14
|
## 0.2.6
|
|
6
15
|
|
|
7
16
|
### New Features
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: clikernel
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.7
|
|
4
4
|
Summary: Serve persistent Jupyter kernels to LLMs as concise text, over MCP or a plain stream protocol
|
|
5
5
|
Author: clikernel contributors
|
|
6
6
|
License: Apache-2.0
|
|
@@ -12,9 +12,9 @@ Requires-Python: >=3.11
|
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE
|
|
14
14
|
Requires-Dist: fastcore>=2.2.2
|
|
15
|
-
Requires-Dist: jupyasyncclient>=0.2.
|
|
15
|
+
Requires-Dist: jupyasyncclient>=0.2.9
|
|
16
16
|
Requires-Dist: fastspec>=0.2.2
|
|
17
|
-
Requires-Dist: mcpmini>=0.0.
|
|
17
|
+
Requires-Dist: mcpmini>=0.0.3
|
|
18
18
|
Requires-Dist: aidialog>=0.0.7
|
|
19
19
|
Requires-Dist: pillow
|
|
20
20
|
Provides-Extra: dev
|
|
@@ -51,7 +51,11 @@ Register the stdio server with your MCP host, e.g. for Claude Code:
|
|
|
51
51
|
claude mcp add clikernel -- clikernel-mcp
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
The tools mirror the gateway’s kernel API
|
|
54
|
+
The tools mirror the gateway’s kernel API: `connect`, `execute`, `list_kernels`, `stop_kernel`, `restart`, and `interrupt`. When executed code requests input, the MCP client shows an elicitation dialog while the same `execute` call remains active. Repeated prompts repeat that callback. Password-marked prompts are refused.
|
|
55
|
+
|
|
56
|
+
An `execute` with no kernel connected auto-creates one, scoped to the conversation: it stops at conversation end, or when `connect` moves elsewhere. Kernels made or attached with an explicit `connect` are stopped only by `stop_kernel` — a later conversation reattaches by id and continues where the last one stopped. `$CLIKERNEL_HOST` overrides the default gateway (`http://127.0.0.1:8787`).
|
|
57
|
+
|
|
58
|
+
Pass `--quiet` (`clikernel-mcp --quiet`) for a host whose sessions should not see banner noise: startup still runs, but its output stays out of every reply, and an auto-connecting `execute` returns just the result.
|
|
55
59
|
|
|
56
60
|
## Configuration
|
|
57
61
|
|
|
@@ -27,7 +27,11 @@ Register the stdio server with your MCP host, e.g. for Claude Code:
|
|
|
27
27
|
claude mcp add clikernel -- clikernel-mcp
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
The tools mirror the gateway’s kernel API
|
|
30
|
+
The tools mirror the gateway’s kernel API: `connect`, `execute`, `list_kernels`, `stop_kernel`, `restart`, and `interrupt`. When executed code requests input, the MCP client shows an elicitation dialog while the same `execute` call remains active. Repeated prompts repeat that callback. Password-marked prompts are refused.
|
|
31
|
+
|
|
32
|
+
An `execute` with no kernel connected auto-creates one, scoped to the conversation: it stops at conversation end, or when `connect` moves elsewhere. Kernels made or attached with an explicit `connect` are stopped only by `stop_kernel` — a later conversation reattaches by id and continues where the last one stopped. `$CLIKERNEL_HOST` overrides the default gateway (`http://127.0.0.1:8787`).
|
|
33
|
+
|
|
34
|
+
Pass `--quiet` (`clikernel-mcp --quiet`) for a host whose sessions should not see banner noise: startup still runs, but its output stays out of every reply, and an auto-connecting `execute` returns just the result.
|
|
31
35
|
|
|
32
36
|
## Configuration
|
|
33
37
|
|
|
@@ -8,4 +8,4 @@ Modules:
|
|
|
8
8
|
- `clikernel.skill`: Use the `clikernel` MCP session as the default workspace for Python work: reading and changing files, notebook work, trying things out, checking how a library behaves, and reshaping data. One session stays open, so imports and variables carry between calls. Read this before writing, running, or debugging Python code in a session with `clikernel` connected.
|
|
9
9
|
- `clikernel.stream`: Streaming JSON-lines worker protocol: nbformat-shaped output events, and a supervisor for select-based UIs."""
|
|
10
10
|
|
|
11
|
-
__version__ = "0.2.
|
|
11
|
+
__version__ = "0.2.7"
|
|
@@ -15,8 +15,11 @@ d = { 'settings': { 'branch': 'main',
|
|
|
15
15
|
'clikernel.cli.main': ('cli.html#main', 'clikernel/cli.py'),
|
|
16
16
|
'clikernel.cli.serve_stream': ('cli.html#serve_stream', 'clikernel/cli.py')},
|
|
17
17
|
'clikernel.core': { 'clikernel.core.Client': ('core.html#client', 'clikernel/core.py'),
|
|
18
|
+
'clikernel.core.Client.__aenter__': ('core.html#client.__aenter__', 'clikernel/core.py'),
|
|
19
|
+
'clikernel.core.Client.__aexit__': ('core.html#client.__aexit__', 'clikernel/core.py'),
|
|
18
20
|
'clikernel.core.Client.__init__': ('core.html#client.__init__', 'clikernel/core.py'),
|
|
19
21
|
'clikernel.core.Client._setup': ('core.html#client._setup', 'clikernel/core.py'),
|
|
22
|
+
'clikernel.core.Client._startkw': ('core.html#client._startkw', 'clikernel/core.py'),
|
|
20
23
|
'clikernel.core.Client._use': ('core.html#client._use', 'clikernel/core.py'),
|
|
21
24
|
'clikernel.core.Client.aclose': ('core.html#client.aclose', 'clikernel/core.py'),
|
|
22
25
|
'clikernel.core.Client.connect': ('core.html#client.connect', 'clikernel/core.py'),
|
|
@@ -97,7 +97,7 @@ STATE_LOST_SETUP = 'NOTE: the kernel restarted with a fresh interpreter: startup
|
|
|
97
97
|
|
|
98
98
|
class Client:
|
|
99
99
|
"One conversation's connection: a gateway manager, and the current kernel"
|
|
100
|
-
def __init__(self, cfgdir=None): self.cfgdir,self.mgr,self.kc,self.kid,self.auto,self.made = cfgdir,None,None,None,False,False
|
|
100
|
+
def __init__(self, cfgdir=None, quiet=False): self.cfgdir,self.quiet,self.mgr,self.kc,self.kid,self.auto,self.made = cfgdir,quiet,None,None,None,False,False
|
|
101
101
|
|
|
102
102
|
async def _use(self, mgr, kid):
|
|
103
103
|
"Point at `kid` on `mgr`, dropping any previous ws (never the kernel)"
|
|
@@ -106,6 +106,12 @@ class Client:
|
|
|
106
106
|
self.kc.start_channels()
|
|
107
107
|
await self.kc.wait_for_ready(timeout=30)
|
|
108
108
|
|
|
109
|
+
def _startkw(self):
|
|
110
|
+
"Creation kwargs for a local kernel: the conversation's cwd and env, with quiet advertised as CLIKERNEL_QUIET"
|
|
111
|
+
env = dict(os.environ)
|
|
112
|
+
if self.quiet: env['CLIKERNEL_QUIET'] = '1'
|
|
113
|
+
return dict(cwd=os.getcwd(), env=env)
|
|
114
|
+
|
|
109
115
|
# %% ../nbs/00_core.ipynb #94497e4a
|
|
110
116
|
@patch
|
|
111
117
|
async def _setup(self:Client):
|
|
@@ -139,19 +145,19 @@ async def connect(self:Client, host='', kernel='', auto=False):
|
|
|
139
145
|
await self._use(mgr, kid)
|
|
140
146
|
self.made = False
|
|
141
147
|
return f'connected to existing kernel {kid} on {url}' + note
|
|
142
|
-
kw =
|
|
148
|
+
kw = self._startkw() if not host else {} # the default gateway is local by definition: kernels start where, and as, the conversation lives (cwd and environment - so kernel-side tools that key state to the conversation, like llmdojo's doc-state, resolve it correctly)
|
|
143
149
|
kid = await mgr.start_kernel(**kw)
|
|
144
150
|
await self._use(mgr, kid)
|
|
145
151
|
self.made = True
|
|
146
152
|
out = await self._setup()
|
|
147
153
|
self.auto = auto
|
|
148
|
-
return f'created kernel {kid} on {url}' + (f'\n{out}' if out.strip() else '') + note
|
|
154
|
+
return f'created kernel {kid} on {url}' + (f'\n{out}' if out.strip() and not self.quiet else '') + note
|
|
149
155
|
|
|
150
156
|
@patch
|
|
151
|
-
async def execute_outs(self:Client, code):
|
|
157
|
+
async def execute_outs(self:Client, code, **kw):
|
|
152
158
|
"Run `code` in the current kernel; nbformat-style output dicts (or a protocol note string)"
|
|
153
159
|
if not self.kc: return 'no kernel: call `connect` first'
|
|
154
|
-
try: return await self.kc.
|
|
160
|
+
try: return await self.kc.exec_outs(code, **kw)
|
|
155
161
|
except DeadKernelError: return 'NOTE: the kernel process died. `connect` to create or attach to another.'
|
|
156
162
|
|
|
157
163
|
@patch
|
|
@@ -198,15 +204,15 @@ async def restart(self:Client):
|
|
|
198
204
|
return f'restart failed ({e.message}); the kernel is still listed: retry, `stop` it, or `connect` for a fresh one'
|
|
199
205
|
old,kw = self.kid,{}
|
|
200
206
|
await self.kc.aclose()
|
|
201
|
-
if self.mgr.base_url == resolve('', self.cfgdir)[0]: kw =
|
|
207
|
+
if self.mgr.base_url == resolve('', self.cfgdir)[0]: kw = self._startkw()
|
|
202
208
|
await self._use(self.mgr, await self.mgr.start_kernel(**kw))
|
|
203
209
|
self.made = True
|
|
204
210
|
out = await self._setup()
|
|
205
|
-
return f'kernel {old} was gone; created fresh kernel {self.kid}.\n' + STATE_LOST_SETUP + (f'\n{out}' if out.strip() else '')
|
|
211
|
+
return f'kernel {old} was gone; created fresh kernel {self.kid}.\n' + STATE_LOST_SETUP + (f'\n{out}' if out.strip() and not self.quiet else '')
|
|
206
212
|
await self.kc.wait_for_ready(timeout=30)
|
|
207
213
|
if not self.made: return STATE_LOST
|
|
208
214
|
out = await self._setup()
|
|
209
|
-
return STATE_LOST_SETUP + (f'\n{out}' if out.strip() else '')
|
|
215
|
+
return STATE_LOST_SETUP + (f'\n{out}' if out.strip() and not self.quiet else '')
|
|
210
216
|
|
|
211
217
|
@patch
|
|
212
218
|
async def interrupt(self:Client):
|
|
@@ -220,3 +226,13 @@ async def aclose(self:Client):
|
|
|
220
226
|
"Drop connections; kernels are left exactly as they are"
|
|
221
227
|
if self.kc: await self.kc.aclose()
|
|
222
228
|
self.mgr,self.kc,self.kid = None,None,None
|
|
229
|
+
|
|
230
|
+
# %% ../nbs/00_core.ipynb #6559aa40
|
|
231
|
+
@patch
|
|
232
|
+
async def __aenter__(self:Client): return self
|
|
233
|
+
|
|
234
|
+
@patch
|
|
235
|
+
async def __aexit__(self:Client, *exc):
|
|
236
|
+
"Stop the current kernel if this client created it (an attached kernel is left as found), then drop connections"
|
|
237
|
+
if self.made and self.kid: await self.stop()
|
|
238
|
+
await self.aclose()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""The MCP frontend: `Client` as tools on stdio
|
|
2
2
|
|
|
3
|
-
The frontend Claude Code launches per conversation
|
|
3
|
+
The frontend Claude Code launches per conversation. `mk_server` closes the tools over a `Client`, and `main` serves them on stdio through mcpmini. The server answers `initialize` without starting a kernel. The first `execute` auto-connects when needed. `connect` remains available for attaching, selecting another gateway, or creating a kernel that outlives the conversation. A kernel `input_request` becomes an MCP elicitation inside the same `execute` call. jupywire sends the elicitation response back to the requesting kernel.
|
|
4
4
|
|
|
5
5
|
Docs: https://AnswerDotAI.github.io/clikernel/mcp.html.md"""
|
|
6
6
|
|
|
@@ -12,6 +12,7 @@ __all__ = ['part2block', 'mk_server', 'main']
|
|
|
12
12
|
# %% ../nbs/01_mcp.ipynb #28c42902
|
|
13
13
|
import asyncio
|
|
14
14
|
from fastcore.utils import *
|
|
15
|
+
from fastcore.script import call_parse, store_true
|
|
15
16
|
from mcpmini.core import MCPServer, serve_stdio
|
|
16
17
|
from aidialog.dialog import Message
|
|
17
18
|
from aidialog.hist import output_parts, merge_media
|
|
@@ -32,21 +33,32 @@ def part2block(p):
|
|
|
32
33
|
def mk_server(c:Client):
|
|
33
34
|
"An `MCPServer` whose tools close over `c`: connect, execute, and the lifecycle verbs"
|
|
34
35
|
alock = asyncio.Lock()
|
|
36
|
+
input_schema = dict(type='object', properties=dict(value=dict(type='string')), required=['value'])
|
|
37
|
+
|
|
38
|
+
async def _input(msg):
|
|
39
|
+
content = msg['content']
|
|
40
|
+
if content.get('password'): raise RuntimeError('password prompts are not supported through MCP')
|
|
41
|
+
r = await srv.elicit(content.get('prompt',''), input_schema)
|
|
42
|
+
if r.get('action') != 'accept': raise RuntimeError(f"input {r.get('action','cancelled')}")
|
|
43
|
+
return r['content']['value']
|
|
44
|
+
|
|
35
45
|
async def connect(
|
|
36
46
|
host:str='', # Gateway: empty for the local default, a `gateways.toml` name, or a URL
|
|
37
47
|
kernel:str='', # Kernel id (or unique prefix) to attach to; empty creates a fresh kernel
|
|
38
48
|
)->str:
|
|
39
|
-
"Connect to a kernel. With `kernel`: attach to that existing kernel exactly as it is (nothing is run) - this is how a later conversation returns to live state, and how to reach a kernel someone else created. Without: create a fresh kernel, run the user's startup.py in it, and install their inspectors; the reply includes the new kernel's id (reusable in a later `connect`)
|
|
49
|
+
"Connect to a kernel. With `kernel`: attach to that existing kernel exactly as it is (nothing is run) - this is how a later conversation returns to live state, and how to reach a kernel someone else created. Without: create a fresh kernel, run the user's startup.py in it, and install their inspectors; the reply includes the new kernel's id (reusable in a later `connect`). Kernels made or attached this way persist until explicitly stopped: disconnecting, switching, and conversation end never kill them. (Connecting also immediately stops the auto kernel, if `execute` had created one.)"
|
|
40
50
|
return await c.connect(host, kernel)
|
|
41
51
|
|
|
42
52
|
async def execute(
|
|
43
53
|
code:str, # Python/IPython code to run
|
|
44
54
|
):
|
|
45
|
-
"Run `code` in the current kernel, keeping state across calls (imports, variables, monkeypatches, cached objects). With no kernel connected, one is auto-created first (default gateway, startup.py and inspectors run)
|
|
55
|
+
"Run `code` in the current kernel, keeping state across calls (imports, variables, monkeypatches, cached objects). With no kernel connected, one is auto-created first (default gateway, startup.py and inspectors run). An auto-created kernel is scoped to the conversation: it stops when the conversation ends or when `connect` moves elsewhere; use `connect` for a kernel that should outlive the conversation. Kernel input prompts use the MCP client's elicitation UI. Password prompts are refused. If the reply says the kernel died, `connect` again. Image outputs (plots etc.) come back as image blocks, resized to a token-friendly size, each preceded by its `<media id=...>` tag."
|
|
46
56
|
pre = ''
|
|
47
|
-
async with alock:
|
|
48
|
-
if not c.kc:
|
|
49
|
-
|
|
57
|
+
async with alock:
|
|
58
|
+
if not c.kc:
|
|
59
|
+
banner = await c.connect(auto=True)
|
|
60
|
+
if not c.quiet: pre = banner + '\n'
|
|
61
|
+
r = await c.execute_outs(code, on_stdin=_input)
|
|
50
62
|
if isinstance(r, str): return pre + r
|
|
51
63
|
res = merge_media(render_text(r, tb_maxlen=MAXLEN), output_parts(Message(msg_type='code', output=r)))
|
|
52
64
|
if isinstance(res, str): return pre + res
|
|
@@ -74,14 +86,21 @@ def mk_server(c:Client):
|
|
|
74
86
|
"Interrupt the code the current kernel is running (SIGINT, i.e. KeyboardInterrupt): the in-flight `execute` returns with a KeyboardInterrupt traceback, and session state survives. Prefer this over `restart` when a call is merely taking too long. Only meaningful while an `execute` is running."
|
|
75
87
|
return await c.interrupt()
|
|
76
88
|
|
|
77
|
-
|
|
89
|
+
if not c.quiet:
|
|
90
|
+
connect.__doc__ += " The startup output also appears in the reply."
|
|
91
|
+
execute.__doc__ += " The connect banner - kernel id and startup output - is prepended to that first reply: read it."
|
|
92
|
+
srv = MCPServer('clikernel', [connect, execute, list_kernels, stop_kernel, restart, interrupt], version=__version__)
|
|
93
|
+
return srv
|
|
78
94
|
|
|
79
95
|
|
|
80
96
|
# %% ../nbs/01_mcp.ipynb #3b90f0e8
|
|
81
|
-
|
|
97
|
+
@call_parse
|
|
98
|
+
def main(
|
|
99
|
+
quiet:store_true=False, # Keep startup output out of replies; an auto-connecting `execute` returns just the result
|
|
100
|
+
):
|
|
82
101
|
"The `clikernel-mcp` console script: the tools on stdio, state is one `Client`"
|
|
83
102
|
async def _main():
|
|
84
|
-
c = Client()
|
|
103
|
+
c = Client(quiet=quiet)
|
|
85
104
|
try: await serve_stdio(mk_server(c))
|
|
86
105
|
finally:
|
|
87
106
|
if c.auto: # an execute-made kernel is conversation-scoped; the gateway may already be gone
|
|
@@ -13,6 +13,8 @@ so the compact protocol exercises the full real stack -- which is its point:
|
|
|
13
13
|
a self-contained test client, and a reminder to keep the layers flexible.
|
|
14
14
|
"""
|
|
15
15
|
import json,os,select,signal,subprocess,sys,time
|
|
16
|
+
from fastcore.nbio import msg2out
|
|
17
|
+
from jupywire.route import OUTPUT_MSGS
|
|
16
18
|
|
|
17
19
|
def _emit(obj):
|
|
18
20
|
sys.stdout.write(json.dumps(obj) + '\n')
|
|
@@ -20,7 +22,9 @@ def _emit(obj):
|
|
|
20
22
|
|
|
21
23
|
async def _do_exec(kc, req):
|
|
22
24
|
rid = req.get('id')
|
|
23
|
-
|
|
25
|
+
def _out(m):
|
|
26
|
+
if m['msg_type'] in OUTPUT_MSGS: _emit(dict(ev='out', id=rid, output=msg2out(m)))
|
|
27
|
+
await kc.run(req['code'], on_output=_out)
|
|
24
28
|
_emit({'ev':'done','id':rid})
|
|
25
29
|
|
|
26
30
|
async def _do_complete(kc, req):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: clikernel
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.7
|
|
4
4
|
Summary: Serve persistent Jupyter kernels to LLMs as concise text, over MCP or a plain stream protocol
|
|
5
5
|
Author: clikernel contributors
|
|
6
6
|
License: Apache-2.0
|
|
@@ -12,9 +12,9 @@ Requires-Python: >=3.11
|
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE
|
|
14
14
|
Requires-Dist: fastcore>=2.2.2
|
|
15
|
-
Requires-Dist: jupyasyncclient>=0.2.
|
|
15
|
+
Requires-Dist: jupyasyncclient>=0.2.9
|
|
16
16
|
Requires-Dist: fastspec>=0.2.2
|
|
17
|
-
Requires-Dist: mcpmini>=0.0.
|
|
17
|
+
Requires-Dist: mcpmini>=0.0.3
|
|
18
18
|
Requires-Dist: aidialog>=0.0.7
|
|
19
19
|
Requires-Dist: pillow
|
|
20
20
|
Provides-Extra: dev
|
|
@@ -51,7 +51,11 @@ Register the stdio server with your MCP host, e.g. for Claude Code:
|
|
|
51
51
|
claude mcp add clikernel -- clikernel-mcp
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
The tools mirror the gateway’s kernel API
|
|
54
|
+
The tools mirror the gateway’s kernel API: `connect`, `execute`, `list_kernels`, `stop_kernel`, `restart`, and `interrupt`. When executed code requests input, the MCP client shows an elicitation dialog while the same `execute` call remains active. Repeated prompts repeat that callback. Password-marked prompts are refused.
|
|
55
|
+
|
|
56
|
+
An `execute` with no kernel connected auto-creates one, scoped to the conversation: it stops at conversation end, or when `connect` moves elsewhere. Kernels made or attached with an explicit `connect` are stopped only by `stop_kernel` — a later conversation reattaches by id and continues where the last one stopped. `$CLIKERNEL_HOST` overrides the default gateway (`http://127.0.0.1:8787`).
|
|
57
|
+
|
|
58
|
+
Pass `--quiet` (`clikernel-mcp --quiet`) for a host whose sessions should not see banner noise: startup still runs, but its output stays out of every reply, and an auto-connecting `execute` returns just the result.
|
|
55
59
|
|
|
56
60
|
## Configuration
|
|
57
61
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|