pi-mcp-py 0.1.0__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.
- pi_mcp_py-0.1.0/.gitignore +34 -0
- pi_mcp_py-0.1.0/PKG-INFO +83 -0
- pi_mcp_py-0.1.0/README.md +66 -0
- pi_mcp_py-0.1.0/pi_mcp/__init__.py +71 -0
- pi_mcp_py-0.1.0/pi_mcp/connection.py +439 -0
- pi_mcp_py-0.1.0/pi_mcp/errors.py +139 -0
- pi_mcp_py-0.1.0/pi_mcp/manager.py +222 -0
- pi_mcp_py-0.1.0/pi_mcp/redact.py +75 -0
- pi_mcp_py-0.1.0/pi_mcp/settings.py +78 -0
- pi_mcp_py-0.1.0/pi_mcp/tools.py +119 -0
- pi_mcp_py-0.1.0/pi_mcp/transport.py +209 -0
- pi_mcp_py-0.1.0/pyproject.toml +35 -0
- pi_mcp_py-0.1.0/tests/conftest.py +52 -0
- pi_mcp_py-0.1.0/tests/mcp_support.py +254 -0
- pi_mcp_py-0.1.0/tests/mock_server.py +144 -0
- pi_mcp_py-0.1.0/tests/test_mcp_acp.py +242 -0
- pi_mcp_py-0.1.0/tests/test_mcp_connection.py +654 -0
- pi_mcp_py-0.1.0/tests/test_mcp_extension.py +419 -0
- pi_mcp_py-0.1.0/tests/test_mcp_http.py +213 -0
- pi_mcp_py-0.1.0/tests/test_mcp_units.py +511 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*.egg-info/
|
|
4
|
+
.eggs/
|
|
5
|
+
dist/
|
|
6
|
+
build/
|
|
7
|
+
!tui/crates/build/
|
|
8
|
+
.pytest_cache/
|
|
9
|
+
.pytest-audit/
|
|
10
|
+
.mypy_cache/
|
|
11
|
+
.ruff_cache/
|
|
12
|
+
.venv/
|
|
13
|
+
.venv-*/
|
|
14
|
+
venv/
|
|
15
|
+
.env
|
|
16
|
+
# Rust TUI workspace (Apache-2.0 fork under tui/)
|
|
17
|
+
tui/target/
|
|
18
|
+
**/*.rs.bk
|
|
19
|
+
|
|
20
|
+
# Benchmark evaluation cache and trial artifacts
|
|
21
|
+
.cache/
|
|
22
|
+
.pi-eval/
|
|
23
|
+
|
|
24
|
+
# Temporary files, coverage and logs
|
|
25
|
+
*.log
|
|
26
|
+
*.tmp
|
|
27
|
+
*.bak
|
|
28
|
+
*.swp
|
|
29
|
+
*.orig
|
|
30
|
+
.coverage
|
|
31
|
+
.coverage.*
|
|
32
|
+
coverage.xml
|
|
33
|
+
htmlcov/
|
|
34
|
+
|
pi_mcp_py-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: pi-mcp-py
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Connects the MCP servers an ACP client passes to the pi-python agent (an extension)
|
|
5
|
+
Project-URL: Homepage, https://github.com/zy1233/pi-python
|
|
6
|
+
Project-URL: Repository, https://github.com/zy1233/pi-python
|
|
7
|
+
Author-email: zy1233 <zy1233@users.noreply.github.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Keywords: acp,agent,extension,mcp,pi
|
|
10
|
+
Requires-Python: >=3.11
|
|
11
|
+
Requires-Dist: anyio>=4.5
|
|
12
|
+
Requires-Dist: httpx>=0.27
|
|
13
|
+
Requires-Dist: langchain-mcp-adapters>=0.3.2
|
|
14
|
+
Requires-Dist: mcp<2,>=1.30
|
|
15
|
+
Requires-Dist: pi-agent-core-lc>=0.6.0
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# pi-mcp-py
|
|
19
|
+
|
|
20
|
+
An extension for [pi-python](https://github.com/zy1233/pi-python). It connects the MCP servers that an
|
|
21
|
+
ACP client (an editor such as Zed) passes to the agent, and gives their tools to the model.
|
|
22
|
+
|
|
23
|
+
The agent itself has no MCP client. Without this package, the servers that the editor passes are not
|
|
24
|
+
connected, and the agent says so. With it, the agent connects them.
|
|
25
|
+
|
|
26
|
+
Install it into the environment of the agent:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install pi-mcp-py
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The package is on PyPI from the 0.6.0 release of pi-python. In a checkout of the repository, use
|
|
33
|
+
`pip install -e ./packages/pi-mcp`.
|
|
34
|
+
|
|
35
|
+
Nothing else to set up. The servers come from the editor (Zed: `context_servers` in the settings).
|
|
36
|
+
It needs `pi-agent-core-lc` 0.6.0 or later: an older core does not hand over the servers of the
|
|
37
|
+
client, and then the package logs a warning and does nothing.
|
|
38
|
+
|
|
39
|
+
## What it does
|
|
40
|
+
|
|
41
|
+
- Connects `stdio`, `http` (Streamable HTTP) and `sse` servers. One connection for each server and
|
|
42
|
+
session. A server that does not start does not stop the session, nor the other servers.
|
|
43
|
+
- Gives each tool to the model as `mcp__<server>__<tool>`. The prefix keeps an MCP tool from replacing a
|
|
44
|
+
built-in tool of the same name. A name longer than 64 characters is cut and gets a hash at the end.
|
|
45
|
+
- Tells the user when a server fails to start or is slow. It says nothing when all is well.
|
|
46
|
+
- Connects a server again when it has stopped: the next tool call does it, at most 3 times in a row (a
|
|
47
|
+
call that gets an answer starts the count again). A call that was already sent when the server died
|
|
48
|
+
is not sent again, because the server may have run it. It fails with the reason.
|
|
49
|
+
- `/mcp` shows the servers, their state and the number of tools. `/mcp reconnect <name>` connects one
|
|
50
|
+
again, with no limit.
|
|
51
|
+
- Ends every server process when the session ends (Windows and Linux).
|
|
52
|
+
- Limits: a server may take 60 s to start and a call 120 s (see **Settings**). The first turn waits at
|
|
53
|
+
most 10 s for a server that still starts. A tool result of more than 50 KB of text is cut, and a note
|
|
54
|
+
says so.
|
|
55
|
+
|
|
56
|
+
## Things to know
|
|
57
|
+
|
|
58
|
+
- **Permissions.** A tool call is asked about in the `ask` mode of the CLI, unless the server marks the
|
|
59
|
+
tool with a hint that says it is harmless (`readOnlyHint`). The hints are taken as the server gives
|
|
60
|
+
them: you chose the server.
|
|
61
|
+
- **Environment of a stdio server.** It gets the safe list of the MCP SDK, the proxy and certificate
|
|
62
|
+
variables of the agent (`HTTP_PROXY`, `SSL_CERT_FILE`, ...), and the `env` of the editor. It does not
|
|
63
|
+
get the other variables of the agent, the LLM keys among them. `${VAR}` in a value is not expanded.
|
|
64
|
+
- **Secrets.** The `env`, `headers`, `args` and `url` of a server are not written to a log, a notice, the
|
|
65
|
+
`/mcp` output or an error text.
|
|
66
|
+
- **Logs.** The stderr of a stdio server goes to `<PI_HOME>/logs/mcp/<name>.log` (`PI_HOME` is
|
|
67
|
+
`~/.pi-python` when it is not set). The file is appended to, and started over when it is larger than
|
|
68
|
+
512 KB. The text of the file is what the server wrote: it may hold what the server was given.
|
|
69
|
+
- **Servers on this machine.** An `http` or `sse` server at `localhost`, `127.0.0.1` or `::1` is
|
|
70
|
+
reached directly, not through the proxy of the system (`httpx` would send it there).
|
|
71
|
+
- **Not supported:** MCP resources, prompts, sampling, roots, elicitation, OAuth, `tools/list_changed`,
|
|
72
|
+
websocket servers.
|
|
73
|
+
|
|
74
|
+
## Settings
|
|
75
|
+
|
|
76
|
+
Environment variables only:
|
|
77
|
+
|
|
78
|
+
| Variable | Default | Meaning |
|
|
79
|
+
|----------|---------|---------|
|
|
80
|
+
| `PI_MCP_STARTUP_TIMEOUT` | 60 | Seconds a server may take to start. Then it counts as failed. |
|
|
81
|
+
| `PI_MCP_CALL_TIMEOUT` | 120 | Seconds a tool call may take. |
|
|
82
|
+
|
|
83
|
+
The design is in `docs/specs/2026-10-23-mcp-extension-design.md` of the repository.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# pi-mcp-py
|
|
2
|
+
|
|
3
|
+
An extension for [pi-python](https://github.com/zy1233/pi-python). It connects the MCP servers that an
|
|
4
|
+
ACP client (an editor such as Zed) passes to the agent, and gives their tools to the model.
|
|
5
|
+
|
|
6
|
+
The agent itself has no MCP client. Without this package, the servers that the editor passes are not
|
|
7
|
+
connected, and the agent says so. With it, the agent connects them.
|
|
8
|
+
|
|
9
|
+
Install it into the environment of the agent:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install pi-mcp-py
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The package is on PyPI from the 0.6.0 release of pi-python. In a checkout of the repository, use
|
|
16
|
+
`pip install -e ./packages/pi-mcp`.
|
|
17
|
+
|
|
18
|
+
Nothing else to set up. The servers come from the editor (Zed: `context_servers` in the settings).
|
|
19
|
+
It needs `pi-agent-core-lc` 0.6.0 or later: an older core does not hand over the servers of the
|
|
20
|
+
client, and then the package logs a warning and does nothing.
|
|
21
|
+
|
|
22
|
+
## What it does
|
|
23
|
+
|
|
24
|
+
- Connects `stdio`, `http` (Streamable HTTP) and `sse` servers. One connection for each server and
|
|
25
|
+
session. A server that does not start does not stop the session, nor the other servers.
|
|
26
|
+
- Gives each tool to the model as `mcp__<server>__<tool>`. The prefix keeps an MCP tool from replacing a
|
|
27
|
+
built-in tool of the same name. A name longer than 64 characters is cut and gets a hash at the end.
|
|
28
|
+
- Tells the user when a server fails to start or is slow. It says nothing when all is well.
|
|
29
|
+
- Connects a server again when it has stopped: the next tool call does it, at most 3 times in a row (a
|
|
30
|
+
call that gets an answer starts the count again). A call that was already sent when the server died
|
|
31
|
+
is not sent again, because the server may have run it. It fails with the reason.
|
|
32
|
+
- `/mcp` shows the servers, their state and the number of tools. `/mcp reconnect <name>` connects one
|
|
33
|
+
again, with no limit.
|
|
34
|
+
- Ends every server process when the session ends (Windows and Linux).
|
|
35
|
+
- Limits: a server may take 60 s to start and a call 120 s (see **Settings**). The first turn waits at
|
|
36
|
+
most 10 s for a server that still starts. A tool result of more than 50 KB of text is cut, and a note
|
|
37
|
+
says so.
|
|
38
|
+
|
|
39
|
+
## Things to know
|
|
40
|
+
|
|
41
|
+
- **Permissions.** A tool call is asked about in the `ask` mode of the CLI, unless the server marks the
|
|
42
|
+
tool with a hint that says it is harmless (`readOnlyHint`). The hints are taken as the server gives
|
|
43
|
+
them: you chose the server.
|
|
44
|
+
- **Environment of a stdio server.** It gets the safe list of the MCP SDK, the proxy and certificate
|
|
45
|
+
variables of the agent (`HTTP_PROXY`, `SSL_CERT_FILE`, ...), and the `env` of the editor. It does not
|
|
46
|
+
get the other variables of the agent, the LLM keys among them. `${VAR}` in a value is not expanded.
|
|
47
|
+
- **Secrets.** The `env`, `headers`, `args` and `url` of a server are not written to a log, a notice, the
|
|
48
|
+
`/mcp` output or an error text.
|
|
49
|
+
- **Logs.** The stderr of a stdio server goes to `<PI_HOME>/logs/mcp/<name>.log` (`PI_HOME` is
|
|
50
|
+
`~/.pi-python` when it is not set). The file is appended to, and started over when it is larger than
|
|
51
|
+
512 KB. The text of the file is what the server wrote: it may hold what the server was given.
|
|
52
|
+
- **Servers on this machine.** An `http` or `sse` server at `localhost`, `127.0.0.1` or `::1` is
|
|
53
|
+
reached directly, not through the proxy of the system (`httpx` would send it there).
|
|
54
|
+
- **Not supported:** MCP resources, prompts, sampling, roots, elicitation, OAuth, `tools/list_changed`,
|
|
55
|
+
websocket servers.
|
|
56
|
+
|
|
57
|
+
## Settings
|
|
58
|
+
|
|
59
|
+
Environment variables only:
|
|
60
|
+
|
|
61
|
+
| Variable | Default | Meaning |
|
|
62
|
+
|----------|---------|---------|
|
|
63
|
+
| `PI_MCP_STARTUP_TIMEOUT` | 60 | Seconds a server may take to start. Then it counts as failed. |
|
|
64
|
+
| `PI_MCP_CALL_TIMEOUT` | 120 | Seconds a tool call may take. |
|
|
65
|
+
|
|
66
|
+
The design is in `docs/specs/2026-10-23-mcp-extension-design.md` of the repository.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""pi-mcp: connect the MCP servers that an ACP client passes (design: docs/specs/2026-10-23-mcp-
|
|
2
|
+
extension-design.md).
|
|
3
|
+
|
|
4
|
+
An editor such as Zed hands the agent its configured MCP servers in ``session/new``,
|
|
5
|
+
``session/load`` and ``session/resume``. The agent has no MCP client of its own. This extension
|
|
6
|
+
connects them: stdio, http and sse servers, one connection per server and session. Their tools
|
|
7
|
+
reach the model as ``mcp__<server>__<tool>``; ``/mcp`` shows the state of the servers.
|
|
8
|
+
|
|
9
|
+
Install: ``pip install pi-mcp-py`` (or ``pip install -e ./packages/pi-mcp`` from a checkout of the
|
|
10
|
+
repository). Nothing is configured here: the servers come from the editor.
|
|
11
|
+
|
|
12
|
+
Environment variables:
|
|
13
|
+
- ``PI_MCP_STARTUP_TIMEOUT`` -- seconds a server may take to start (default 60)
|
|
14
|
+
- ``PI_MCP_CALL_TIMEOUT`` -- seconds a tool call may take (default 120)
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import logging
|
|
20
|
+
from typing import TYPE_CHECKING, Any
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from pi_agent_core.extensions import ExtensionAPI
|
|
24
|
+
|
|
25
|
+
__all__ = ["activate"]
|
|
26
|
+
|
|
27
|
+
logger = logging.getLogger(__name__)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def activate(pi: ExtensionAPI) -> None:
|
|
31
|
+
"""Extension entry point: take over the servers the client passed, start them later.
|
|
32
|
+
|
|
33
|
+
No I/O happens here (a failing ``activate`` is rolled back, and a started child process
|
|
34
|
+
would not be). The servers start in the ``session_start`` hook, each in a task of its own.
|
|
35
|
+
"""
|
|
36
|
+
try:
|
|
37
|
+
servers = tuple(pi.client_mcp_servers)
|
|
38
|
+
except AttributeError:
|
|
39
|
+
logger.warning(
|
|
40
|
+
"pi-mcp needs a newer pi-agent-core-lc (0.6.0 or later): this one does not hand over "
|
|
41
|
+
"the MCP servers of the client. pi-mcp does nothing."
|
|
42
|
+
)
|
|
43
|
+
return
|
|
44
|
+
except RuntimeError: # no harness behind this API (a test, a bare registry)
|
|
45
|
+
servers = ()
|
|
46
|
+
|
|
47
|
+
from pi_mcp.manager import Manager
|
|
48
|
+
from pi_mcp.settings import Settings
|
|
49
|
+
|
|
50
|
+
manager = Manager(pi, servers, settings=Settings.from_env())
|
|
51
|
+
if servers:
|
|
52
|
+
pi.claim_client_mcp_servers([server.name for server in servers])
|
|
53
|
+
|
|
54
|
+
def on_session_start(_event: Any) -> None:
|
|
55
|
+
try:
|
|
56
|
+
manager.start()
|
|
57
|
+
except Exception: # a handler that raises would fail the load of every extension
|
|
58
|
+
logger.warning("pi-mcp could not start the MCP servers", exc_info=True)
|
|
59
|
+
|
|
60
|
+
pi.on("session_start", on_session_start)
|
|
61
|
+
pi.add_turn_barrier(manager.wait_started)
|
|
62
|
+
pi.register_cleanup(manager.close)
|
|
63
|
+
|
|
64
|
+
async def mcp_command(args: str) -> None:
|
|
65
|
+
pi.send_message(await manager.command(args))
|
|
66
|
+
|
|
67
|
+
pi.register_command(
|
|
68
|
+
"mcp",
|
|
69
|
+
description="Show the MCP servers of this session (/mcp reconnect <name> to reconnect)",
|
|
70
|
+
handler=mcp_command,
|
|
71
|
+
)
|