pi-mcp-client 0.7.0 → 0.8.1
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.
- package/README.md +14 -13
- package/dist/index.js +166 -40
- package/docs/authentication.md +1 -1
- package/docs/behavior.md +31 -5
- package/docs/commands.md +27 -21
- package/docs/configuration.md +22 -8
- package/docs/tool-reference.md +13 -13
- package/docs/troubleshooting.md +22 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
# 🔌 Pi MCP Client
|
|
2
2
|
|
|
3
|
-
Connect Pi to MCP servers
|
|
4
|
-
|
|
5
|
-
TypeScript SDK. You can also select, preview, and use server-provided prompts.
|
|
6
|
-
No bridge process or invocation proxy.
|
|
3
|
+
Connect Pi to MCP servers so the model can use their tools and read their
|
|
4
|
+
resources. You can also browse, preview, and use server-provided prompts.
|
|
7
5
|
|
|
8
6
|
## 🚀 Installation
|
|
9
7
|
|
|
@@ -23,15 +21,15 @@ This server doesn't require credentials. Ask Pi:
|
|
|
23
21
|
|
|
24
22
|
> Search Cloudflare's documentation for how to deploy a Worker.
|
|
25
23
|
|
|
26
|
-
You configure servers and
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
You configure servers and sign in when needed. The model finds and uses
|
|
25
|
+
relevant tools and resources—you don't need to select tools before asking a
|
|
26
|
+
question.
|
|
29
27
|
|
|
30
28
|
Use these commands in Pi to manage your connections:
|
|
31
29
|
|
|
32
30
|
| Command | Purpose |
|
|
33
31
|
| --- | --- |
|
|
34
|
-
| `/mcp` |
|
|
32
|
+
| `/mcp` | Check connection status, available-tool counts, and tools loaded for the model when troubleshooting or checking your setup. |
|
|
35
33
|
| `/mcp login <server>` | Sign in to an HTTP server. Only this command opens the login browser. |
|
|
36
34
|
| `/mcp prompt <server> [name] [argument=value ...]` | Browse prompts or open one by name, then review a preview before using it. |
|
|
37
35
|
| `/mcp reload` | Apply changes after editing your MCP configuration files. |
|
|
@@ -43,10 +41,12 @@ permissions. Tool activation isn't a per-call approval prompt. See
|
|
|
43
41
|
## ⚙️ Configuration
|
|
44
42
|
|
|
45
43
|
Store server definitions in `~/.pi/agent/mcp.json` or a trusted project's
|
|
46
|
-
`.mcp.json`. Project
|
|
44
|
+
`.mcp.json`. Project servers load only after an explicit
|
|
45
|
+
[trust decision](docs/behavior.md#project-trust). Project definitions replace
|
|
46
|
+
same-named global definitions in full.
|
|
47
47
|
You can edit these files or use `/mcp add` and `/mcp remove`. To reuse a
|
|
48
48
|
Claude/Cursor JSON or Codex TOML file, run `/mcp import --scope global <path>` and
|
|
49
|
-
review the selected connections before saving.
|
|
49
|
+
review the selected connections before saving.
|
|
50
50
|
|
|
51
51
|
Detailed guides:
|
|
52
52
|
|
|
@@ -57,14 +57,15 @@ Detailed guides:
|
|
|
57
57
|
- [Commands](docs/commands.md): Server management, tool browsing, prompt selection,
|
|
58
58
|
and resource watches. These are commands **you** run in Pi.
|
|
59
59
|
- [Tool reference](docs/tool-reference.md): Discovery, activation, resource reads,
|
|
60
|
-
and argument completions. This is the **
|
|
61
|
-
- [Behavior](docs/behavior.md):
|
|
60
|
+
and argument completions. This is the **model's** interface, not a user API.
|
|
61
|
+
- [Behavior](docs/behavior.md): When servers connect, when tools become available,
|
|
62
|
+
and what permissions they have.
|
|
62
63
|
- [Troubleshooting](docs/troubleshooting.md): Error codes, recovery, and large
|
|
63
64
|
results.
|
|
64
65
|
|
|
65
66
|
## 🧰 Requirements
|
|
66
67
|
|
|
67
|
-
- Pi 0.85.1 or later
|
|
68
|
+
- Pi 0.85.1 or later.
|
|
68
69
|
- Node.js 22 or later.
|
|
69
70
|
- The server executable for stdio connections.
|
|
70
71
|
- An available OS credential store for OAuth. Linux requires a working Secret
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
2
3
|
import { join as join4 } from "node:path";
|
|
3
4
|
import {
|
|
4
5
|
BorderedLoader as BorderedLoader2,
|
|
@@ -2329,7 +2330,7 @@ async function inspectConfigScopes(agentDir, cwd, trusted) {
|
|
|
2329
2330
|
async function updateServerConfig(agentDir, cwd, trusted, mutation, validate) {
|
|
2330
2331
|
const scoped = mutation.action !== "toggle";
|
|
2331
2332
|
if (scoped && mutation.scope === "project" && !trusted)
|
|
2332
|
-
throw new ConfigMutationError("Project configuration requires a trusted project. Use global scope or trust
|
|
2333
|
+
throw new ConfigMutationError("Project configuration requires a trusted project. Use global scope, or run /trust to trust this folder first.");
|
|
2333
2334
|
const paths = [join(agentDir, "mcp.json"), ...trusted ? [join(cwd, ".mcp.json")] : []];
|
|
2334
2335
|
const targets = await Promise.all(paths.map(configTarget));
|
|
2335
2336
|
if (scoped && targets.length === 2 && targets[0] === targets[1])
|
|
@@ -3973,16 +3974,16 @@ function importAction(name, scope, scopes) {
|
|
|
3973
3974
|
if (scope === "project" && Object.hasOwn(scopes.global, name)) return "Override global definition";
|
|
3974
3975
|
return `Add ${scope} definition`;
|
|
3975
3976
|
}
|
|
3976
|
-
async function runImportCommand(input, ctx, agentDir, signal, assertCurrent, save) {
|
|
3977
|
+
async function runImportCommand(input, ctx, agentDir, projectTrusted, signal, assertCurrent, save) {
|
|
3977
3978
|
if (!ctx.hasUI) throw new ConfigMutationError("Configuration imports require an interactive session (TUI or RPC).");
|
|
3978
3979
|
const { scope, path } = parseImportCommand(input);
|
|
3979
|
-
const trusted =
|
|
3980
|
+
const trusted = projectTrusted();
|
|
3980
3981
|
if (scope === "project" && !trusted)
|
|
3981
|
-
throw new ConfigMutationError("Project configuration requires a trusted project. Use global scope or trust
|
|
3982
|
+
throw new ConfigMutationError("Project configuration requires a trusted project. Use global scope, or run /trust to trust this folder first.");
|
|
3982
3983
|
const guard = () => {
|
|
3983
3984
|
signal.throwIfAborted();
|
|
3984
3985
|
assertCurrent();
|
|
3985
|
-
if (
|
|
3986
|
+
if (projectTrusted() !== trusted)
|
|
3986
3987
|
throw new ConfigMutationError("Project trust changed during the preview. Run /mcp import again; nothing was saved.");
|
|
3987
3988
|
};
|
|
3988
3989
|
const select = async (title, choices) => {
|
|
@@ -4541,33 +4542,61 @@ async function authenticate(identity, open2, signal, store, options = {}) {
|
|
|
4541
4542
|
}
|
|
4542
4543
|
|
|
4543
4544
|
// src/management.ts
|
|
4544
|
-
import { truncateToWidth as truncateToWidth2 } from "@earendil-works/pi-tui";
|
|
4545
|
+
import { truncateToWidth as truncateToWidth2, visibleWidth, wrapTextWithAnsi } from "@earendil-works/pi-tui";
|
|
4545
4546
|
var serverStates = {
|
|
4546
|
-
disconnected: { glyph: "\u25CB", label: "idle" },
|
|
4547
|
-
connected: { glyph: "\u25CF", label: "connected" },
|
|
4548
|
-
connecting: { glyph: "\u25B6\uFE0E", label: "connecting" },
|
|
4549
|
-
failed: { glyph: "\u2718\uFE0E", label: "error" },
|
|
4550
|
-
disabled: { glyph: "\u25CB", label: "disabled" }
|
|
4547
|
+
disconnected: { glyph: "\u25CB", label: "idle", color: "muted" },
|
|
4548
|
+
connected: { glyph: "\u25CF", label: "connected", color: "success" },
|
|
4549
|
+
connecting: { glyph: "\u25B6\uFE0E", label: "connecting", color: "warning" },
|
|
4550
|
+
failed: { glyph: "\u2718\uFE0E", label: "error", color: "error" },
|
|
4551
|
+
disabled: { glyph: "\u25CB", label: "disabled", color: "dim" }
|
|
4551
4552
|
};
|
|
4552
|
-
function serverMatrix(servers, loaded, width = 80) {
|
|
4553
|
+
function serverMatrix(servers, loaded, width = 80, theme) {
|
|
4553
4554
|
if (width <= 0) return "";
|
|
4554
|
-
const
|
|
4555
|
-
|
|
4556
|
-
const
|
|
4557
|
-
|
|
4558
|
-
|
|
4555
|
+
const fg = (color, text) => theme ? theme.fg(color, text) : text;
|
|
4556
|
+
const bold = (text) => theme ? theme.bold(text) : text;
|
|
4557
|
+
const fit = (text) => {
|
|
4558
|
+
const fitted = truncateToWidth2(text, width, "\u2026");
|
|
4559
|
+
return theme ? fitted : plain(fitted);
|
|
4560
|
+
};
|
|
4561
|
+
const wrap = (text) => wrapTextWithAnsi(text, width).map(fit);
|
|
4562
|
+
const rows = [];
|
|
4563
|
+
if (!servers.length) return wrap(fg("muted", "No MCP servers configured.")).join("\n");
|
|
4564
|
+
const toolsWidth = Math.max(5, ...servers.map((server) => String(server.catalogSize ?? "\u2014").length));
|
|
4565
|
+
const loadedWidth = Math.max(6, ...servers.map((server) => String(loaded.get(server.name) ?? 0).length));
|
|
4566
|
+
const fixedWidth = 18 + toolsWidth + loadedWidth;
|
|
4567
|
+
const compact = width < fixedWidth + 12;
|
|
4568
|
+
const nameWidth = Math.max(0, Math.min(
|
|
4569
|
+
40,
|
|
4570
|
+
width - fixedWidth,
|
|
4571
|
+
Math.max(6, ...servers.map(({ name }) => visibleWidth(line(name))))
|
|
4572
|
+
));
|
|
4573
|
+
const padName = (name) => {
|
|
4574
|
+
const text = plain(truncateToWidth2(line(name), nameWidth, "\u2026"));
|
|
4575
|
+
return text + " ".repeat(Math.max(0, nameWidth - visibleWidth(text)));
|
|
4576
|
+
};
|
|
4577
|
+
if (!compact) rows.push(fg("muted", bold(
|
|
4578
|
+
` ${"Server".padEnd(nameWidth)} ${"State".padEnd(10)} ${"Tools".padStart(toolsWidth)} ${"Loaded".padStart(loadedWidth)}`
|
|
4579
|
+
)));
|
|
4580
|
+
for (const server of servers) {
|
|
4559
4581
|
const state = serverStates[server.state];
|
|
4560
|
-
const
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4582
|
+
const count = loaded.get(server.name) ?? 0;
|
|
4583
|
+
const tools = String(server.catalogSize ?? "\u2014");
|
|
4584
|
+
const name = fg(server.state === "disabled" ? "dim" : "text", bold(compact ? line(server.name) : padName(server.name)));
|
|
4585
|
+
const glyph = fg(state.color, state.glyph);
|
|
4586
|
+
if (compact) {
|
|
4587
|
+
rows.push(...wrap(`${glyph} ${name}`));
|
|
4588
|
+
rows.push(...wrap(` ${fg(state.color, state.label)} \xB7 ${fg("muted", `${tools} tools \xB7 ${count} loaded`)}`));
|
|
4589
|
+
} else {
|
|
4590
|
+
rows.push(`${glyph} ${name} ${fg(state.color, state.label.padEnd(10))} ` + fg(server.catalogSize === void 0 ? "dim" : "text", tools.padStart(toolsWidth)) + " " + fg(count ? "accent" : "dim", String(count).padStart(loadedWidth)));
|
|
4591
|
+
}
|
|
4592
|
+
}
|
|
4593
|
+
rows.push("", ...wrap(fg("dim", "Connections open on demand. \u2014 = catalog not fetched.")));
|
|
4594
|
+
const errors = servers.filter((server) => server.state === "failed" && server.error);
|
|
4595
|
+
if (errors.length) rows.push("");
|
|
4596
|
+
for (const server of errors) {
|
|
4597
|
+
rows.push(...wrap(fg("error", `\u2718\uFE0E ${line(server.name)}: [${line(server.error.code)}]`) + fg("muted", ` ${line(server.error.message)}`)));
|
|
4598
|
+
}
|
|
4599
|
+
return rows.map(fit).join("\n");
|
|
4571
4600
|
}
|
|
4572
4601
|
function toolPickerLabel(tool, index, columns = 80) {
|
|
4573
4602
|
const width = Math.max(0, columns - 4);
|
|
@@ -5913,6 +5942,58 @@ function renderResult(result, options, theme, isError) {
|
|
|
5913
5942
|
};
|
|
5914
5943
|
}
|
|
5915
5944
|
|
|
5945
|
+
// src/status-panel.ts
|
|
5946
|
+
var STATUS_ENTRY = "mcp-status";
|
|
5947
|
+
function statusPanel(snapshot, theme) {
|
|
5948
|
+
const loaded = new Map(snapshot.loaded);
|
|
5949
|
+
return {
|
|
5950
|
+
render(width) {
|
|
5951
|
+
if (width <= 0) return [];
|
|
5952
|
+
const padding = width > 2 ? 1 : 0;
|
|
5953
|
+
const prefix = " ".repeat(padding);
|
|
5954
|
+
return serverMatrix(snapshot.servers, loaded, width - padding * 2, theme).split("\n").map((row) => prefix + row);
|
|
5955
|
+
},
|
|
5956
|
+
// Styling and layout are recomputed on every render, including theme changes.
|
|
5957
|
+
invalidate() {
|
|
5958
|
+
}
|
|
5959
|
+
};
|
|
5960
|
+
}
|
|
5961
|
+
|
|
5962
|
+
// src/trust.ts
|
|
5963
|
+
import {
|
|
5964
|
+
hasTrustRequiringProjectResources,
|
|
5965
|
+
ProjectTrustStore,
|
|
5966
|
+
SettingsManager
|
|
5967
|
+
} from "@earendil-works/pi-coding-agent";
|
|
5968
|
+
var CHOICES = /* @__PURE__ */ new Map([
|
|
5969
|
+
["Trust", { trusted: true, save: true }],
|
|
5970
|
+
["Trust (this session only)", { trusted: true, save: false }],
|
|
5971
|
+
["Do not trust", { trusted: false, save: true }],
|
|
5972
|
+
["Do not trust (this session only)", { trusted: false, save: false }]
|
|
5973
|
+
]);
|
|
5974
|
+
function projectTrustDecision(agentDir, cwd, piTrusted) {
|
|
5975
|
+
if (!piTrusted) return false;
|
|
5976
|
+
if (hasTrustRequiringProjectResources(cwd)) return true;
|
|
5977
|
+
const saved = new ProjectTrustStore(agentDir).get(cwd);
|
|
5978
|
+
if (saved !== null) return saved;
|
|
5979
|
+
const policy = SettingsManager.create(cwd, agentDir, { projectTrusted: false }).getDefaultProjectTrust();
|
|
5980
|
+
return policy === "ask" ? void 0 : policy === "always";
|
|
5981
|
+
}
|
|
5982
|
+
async function askProjectTrust(agentDir, cwd, select, signal) {
|
|
5983
|
+
const answer = await select(
|
|
5984
|
+
`Trust project folder?
|
|
5985
|
+
${cwd}
|
|
5986
|
+
|
|
5987
|
+
Its .mcp.json defines MCP servers, which can run local commands with your permissions. Saved decisions use Pi's project trust and also apply to Pi project resources.`,
|
|
5988
|
+
[...CHOICES.keys()],
|
|
5989
|
+
{ signal }
|
|
5990
|
+
);
|
|
5991
|
+
const choice = answer === void 0 ? void 0 : CHOICES.get(answer);
|
|
5992
|
+
if (!choice || signal.aborted) return void 0;
|
|
5993
|
+
if (choice.save) new ProjectTrustStore(agentDir).set(cwd, choice.trusted);
|
|
5994
|
+
return choice.trusted;
|
|
5995
|
+
}
|
|
5996
|
+
|
|
5916
5997
|
// src/index.ts
|
|
5917
5998
|
var CommandUsageError = class extends Error {
|
|
5918
5999
|
};
|
|
@@ -5941,6 +6022,12 @@ function mcpClient(pi, options = {}) {
|
|
|
5941
6022
|
let loginController;
|
|
5942
6023
|
let promptController;
|
|
5943
6024
|
let importController;
|
|
6025
|
+
let trustController;
|
|
6026
|
+
let sessionTrust;
|
|
6027
|
+
pi.registerEntryRenderer(
|
|
6028
|
+
STATUS_ENTRY,
|
|
6029
|
+
(entry, _options, theme) => statusPanel(entry.data ?? { servers: [], loaded: [] }, theme)
|
|
6030
|
+
);
|
|
5944
6031
|
pi.registerMessageRenderer("mcp-prompt", (message, { expanded, outputPad }, theme) => {
|
|
5945
6032
|
const details = object(message.details) ? message.details : {};
|
|
5946
6033
|
const count = Number(details.count ?? 0);
|
|
@@ -6004,6 +6091,35 @@ Text output is limited to 2000 lines or 50 KiB; larger results are saved to a pr
|
|
|
6004
6091
|
}
|
|
6005
6092
|
});
|
|
6006
6093
|
}
|
|
6094
|
+
const trustDecision = (ctx) => projectTrustDecision(agentDir, ctx.cwd, ctx.isProjectTrusted()) ?? (sessionTrust?.cwd === ctx.cwd ? sessionTrust.trusted : void 0);
|
|
6095
|
+
const projectTrusted = (ctx) => trustDecision(ctx) ?? false;
|
|
6096
|
+
async function resolveProjectTrust(ctx) {
|
|
6097
|
+
let trusted = trustDecision(ctx);
|
|
6098
|
+
if (!existsSync(join4(ctx.cwd, ".mcp.json"))) return trusted ?? false;
|
|
6099
|
+
let answered = false;
|
|
6100
|
+
if (trusted === void 0 && ctx.hasUI) {
|
|
6101
|
+
const controller = new AbortController();
|
|
6102
|
+
trustController = controller;
|
|
6103
|
+
try {
|
|
6104
|
+
trusted = await askProjectTrust(
|
|
6105
|
+
agentDir,
|
|
6106
|
+
ctx.cwd,
|
|
6107
|
+
ctx.ui.select.bind(ctx.ui),
|
|
6108
|
+
AbortSignal.any([controller.signal, ...ctx.signal ? [ctx.signal] : []])
|
|
6109
|
+
);
|
|
6110
|
+
} finally {
|
|
6111
|
+
if (trustController === controller) trustController = void 0;
|
|
6112
|
+
}
|
|
6113
|
+
if (controller.signal.aborted) return false;
|
|
6114
|
+
if (trusted !== void 0) {
|
|
6115
|
+
sessionTrust = { cwd: ctx.cwd, trusted };
|
|
6116
|
+
answered = true;
|
|
6117
|
+
}
|
|
6118
|
+
}
|
|
6119
|
+
if (!trusted && !answered && ctx.hasUI && ctx.isProjectTrusted())
|
|
6120
|
+
ctx.ui.notify("Project .mcp.json ignored: this folder isn't trusted for MCP servers. Run /trust to save a decision, then /mcp reload.", "warning");
|
|
6121
|
+
return trusted ?? false;
|
|
6122
|
+
}
|
|
6007
6123
|
const restore = (ctx) => {
|
|
6008
6124
|
const tools = restoredTools(ctx.sessionManager.getBranch()).filter((tool) => {
|
|
6009
6125
|
try {
|
|
@@ -6038,14 +6154,15 @@ Text output is limited to 2000 lines or 50 KiB; larger results are saved to a pr
|
|
|
6038
6154
|
}
|
|
6039
6155
|
};
|
|
6040
6156
|
ctx.signal?.throwIfAborted();
|
|
6157
|
+
const trusted = mutation ? projectTrusted(ctx) : await resolveProjectTrust(ctx);
|
|
6041
6158
|
const update = mutation && await updateServerConfig(
|
|
6042
6159
|
agentDir,
|
|
6043
6160
|
ctx.cwd,
|
|
6044
|
-
|
|
6161
|
+
trusted,
|
|
6045
6162
|
mutation,
|
|
6046
6163
|
validate
|
|
6047
6164
|
);
|
|
6048
|
-
const nextConfig = update ? update.config : await loadConfig(agentDir, ctx.cwd,
|
|
6165
|
+
const nextConfig = update ? update.config : await loadConfig(agentDir, ctx.cwd, trusted);
|
|
6049
6166
|
validate(nextConfig);
|
|
6050
6167
|
const next = new McpRuntime(
|
|
6051
6168
|
nextConfig,
|
|
@@ -6073,15 +6190,18 @@ Text output is limited to 2000 lines or 50 KiB; larger results are saved to a pr
|
|
|
6073
6190
|
return update?.scope;
|
|
6074
6191
|
}
|
|
6075
6192
|
pi.on("session_start", async (_event, ctx) => {
|
|
6076
|
-
sessionGeneration
|
|
6193
|
+
const generation = ++sessionGeneration;
|
|
6077
6194
|
promptController?.abort();
|
|
6078
6195
|
importController?.abort();
|
|
6196
|
+
trustController?.abort();
|
|
6079
6197
|
await runtime?.close();
|
|
6080
6198
|
runtime = void 0;
|
|
6081
6199
|
config = {};
|
|
6082
6200
|
configError = void 0;
|
|
6083
6201
|
try {
|
|
6084
|
-
|
|
6202
|
+
const trusted = await resolveProjectTrust(ctx);
|
|
6203
|
+
if (generation !== sessionGeneration) return;
|
|
6204
|
+
config = await loadConfig(agentDir, ctx.cwd, trusted);
|
|
6085
6205
|
runtime = new McpRuntime(config, ctx.cwd, join4(agentDir, "cache", "pi-mcp-client"), createSdkConnector(storeFactory));
|
|
6086
6206
|
resourceNotifications(runtime, ctx);
|
|
6087
6207
|
} catch (error) {
|
|
@@ -6101,6 +6221,7 @@ Text output is limited to 2000 lines or 50 KiB; larger results are saved to a pr
|
|
|
6101
6221
|
loginController?.abort();
|
|
6102
6222
|
promptController?.abort();
|
|
6103
6223
|
importController?.abort();
|
|
6224
|
+
trustController?.abort();
|
|
6104
6225
|
const old = runtime;
|
|
6105
6226
|
runtime = void 0;
|
|
6106
6227
|
await old?.close();
|
|
@@ -6331,7 +6452,7 @@ Variables: ${(candidate.variables ?? []).join(", ") || "none"}. Supply known val
|
|
|
6331
6452
|
}
|
|
6332
6453
|
});
|
|
6333
6454
|
pi.registerCommand("mcp", {
|
|
6334
|
-
description: "
|
|
6455
|
+
description: "Show MCP server status; manage servers: add|remove|import --scope global|project, reload, enable|disable|get|tools|login|logout|reconnect|refresh <server>; prompt <server> [name] [argument=value ...]; subscriptions; subscribe|unsubscribe <server> <uri>",
|
|
6335
6456
|
getArgumentCompletions(prefix) {
|
|
6336
6457
|
const serverActions = ["enable", "disable", "get", "tools", "prompt", "login", "logout", "reconnect", "refresh", "subscribe", "unsubscribe"];
|
|
6337
6458
|
const input = prefix.trimStart();
|
|
@@ -6339,7 +6460,7 @@ Variables: ${(candidate.variables ?? []).join(", ") || "none"}. Supply known val
|
|
|
6339
6460
|
if (configuration !== void 0) return configuration;
|
|
6340
6461
|
const match = /^(\S+)\s+(.*)$/s.exec(input);
|
|
6341
6462
|
if (!match) {
|
|
6342
|
-
return ["
|
|
6463
|
+
return ["reload", "subscriptions", "add", "remove", "import", ...serverActions].filter((action2) => action2.startsWith(input)).map((action2) => ({ value: action2, label: action2 }));
|
|
6343
6464
|
}
|
|
6344
6465
|
const [, action, partialServer] = match;
|
|
6345
6466
|
if (action === "login") {
|
|
@@ -6355,7 +6476,7 @@ Variables: ${(candidate.variables ?? []).join(", ") || "none"}. Supply known val
|
|
|
6355
6476
|
async handler(args, ctx) {
|
|
6356
6477
|
const generation = sessionGeneration;
|
|
6357
6478
|
await ctx.waitForIdle();
|
|
6358
|
-
let [action = "
|
|
6479
|
+
let [action = "", server, ...extra] = args.trim().split(/\s+/).filter(Boolean);
|
|
6359
6480
|
try {
|
|
6360
6481
|
if (generation !== sessionGeneration)
|
|
6361
6482
|
throw new CommandUsageError("The Pi session changed while waiting for idle.");
|
|
@@ -6370,6 +6491,7 @@ Variables: ${(candidate.variables ?? []).join(", ") || "none"}. Supply known val
|
|
|
6370
6491
|
args,
|
|
6371
6492
|
ctx,
|
|
6372
6493
|
agentDir,
|
|
6494
|
+
() => projectTrusted(ctx),
|
|
6373
6495
|
AbortSignal.any([controller.signal, ...ctx.signal ? [ctx.signal] : []]),
|
|
6374
6496
|
() => {
|
|
6375
6497
|
if (sessionGeneration !== generation || runtime !== activeRuntime)
|
|
@@ -6429,7 +6551,7 @@ ${snapshot.body}`,
|
|
|
6429
6551
|
server = mutation.server;
|
|
6430
6552
|
await reloadConfiguration(ctx, mutation);
|
|
6431
6553
|
const remaining = Object.hasOwn(config, server);
|
|
6432
|
-
const message = mutation.action === "add" ? `\u2714\uFE0E ${server}: saved in ${mutation.scope} configuration. Connections, authentication, and tool discovery remain on demand.` + (mutation.scope === "global" && ctx
|
|
6554
|
+
const message = mutation.action === "add" ? `\u2714\uFE0E ${server}: saved in ${mutation.scope} configuration. Connections, authentication, and tool discovery remain on demand.` + (mutation.scope === "global" && projectTrusted(ctx) ? " Trusted project definitions take precedence over global definitions." : "") : `\u2714\uFE0E ${server}: removed from ${mutation.scope} configuration. Credentials were retained.` + (remaining ? " A definition from the other scope remains effective; connections reopen on demand." : " Its connection is closed and its tools are no longer active.");
|
|
6433
6555
|
if (ctx.hasUI) ctx.ui.notify(message, "info");
|
|
6434
6556
|
return;
|
|
6435
6557
|
}
|
|
@@ -6495,19 +6617,23 @@ ${snapshot.body}`,
|
|
|
6495
6617
|
);
|
|
6496
6618
|
return;
|
|
6497
6619
|
}
|
|
6498
|
-
if (
|
|
6620
|
+
if (!action) {
|
|
6499
6621
|
const statuses = current().serverStatuses();
|
|
6500
6622
|
const loaded = /* @__PURE__ */ new Map();
|
|
6501
6623
|
for (const name of pi.getActiveTools()) {
|
|
6502
6624
|
const tool = exposure.definitions.get(name);
|
|
6503
6625
|
if (tool) loaded.set(tool.server, (loaded.get(tool.server) ?? 0) + 1);
|
|
6504
6626
|
}
|
|
6505
|
-
if (ctx.
|
|
6627
|
+
if (ctx.mode === "tui") {
|
|
6628
|
+
pi.appendEntry(STATUS_ENTRY, { servers: statuses, loaded: [...loaded] });
|
|
6629
|
+
} else if (ctx.hasUI) {
|
|
6630
|
+
ctx.ui.notify(serverMatrix(statuses, loaded), "info");
|
|
6631
|
+
}
|
|
6506
6632
|
return;
|
|
6507
6633
|
}
|
|
6508
6634
|
if (!server || extra.length > 0 && !(action === "login" && extra.length === 1 && extra[0] === "--no-browser") || !Object.hasOwn(config, server) || config[server].disabled)
|
|
6509
6635
|
throw new CommandUsageError(
|
|
6510
|
-
"Usage: /mcp
|
|
6636
|
+
"Usage: /mcp, /mcp reload, /mcp enable|disable|get|tools|login|logout|reconnect|refresh <server>, or /mcp add|remove|import --scope global|project ... . Disabled servers accept enable, disable, get, logout, and scoped removal."
|
|
6511
6637
|
);
|
|
6512
6638
|
if (action === "tools") {
|
|
6513
6639
|
if (!ctx.hasUI)
|
|
@@ -6618,7 +6744,7 @@ Opening browser. Esc to cancel.`
|
|
|
6618
6744
|
await current().promptCatalog(server, ctx.signal, true);
|
|
6619
6745
|
} else
|
|
6620
6746
|
throw new CommandUsageError(
|
|
6621
|
-
"Unknown MCP command. Use /mcp
|
|
6747
|
+
"Unknown MCP command. Use /mcp, /mcp reload, or /mcp enable|disable|get|tools|login|logout|reconnect|refresh <server>, or /mcp add|remove|import --scope global|project ... ."
|
|
6622
6748
|
);
|
|
6623
6749
|
if (ctx.hasUI)
|
|
6624
6750
|
ctx.ui.notify(
|
package/docs/authentication.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[Back to the README](../README.md)
|
|
4
4
|
|
|
5
|
-
You manage authentication through `/mcp login` and `/mcp logout`. The
|
|
5
|
+
You manage authentication through `/mcp login` and `/mcp logout`. The model
|
|
6
6
|
can't initiate an OAuth login: only your explicit login command opens the browser.
|
|
7
7
|
For externally managed bearer tokens, use
|
|
8
8
|
[headers and secret commands](configuration.md#secret-commands) instead.
|
package/docs/behavior.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[Back to the README](../README.md)
|
|
4
4
|
|
|
5
5
|
This page explains how the extension manages state and displays results. For the
|
|
6
|
-
|
|
6
|
+
model's tool-call interface, see the [tool reference](tool-reference.md).
|
|
7
7
|
|
|
8
8
|
## Sessions
|
|
9
9
|
|
|
@@ -15,7 +15,7 @@ assistant's tool-call interface, see the [tool reference](tool-reference.md).
|
|
|
15
15
|
Other providers receive the expanded tool list normally.
|
|
16
16
|
- Discovery respects server filters; activation also respects Pi's tool exclusions.
|
|
17
17
|
An explicit tool allowlist must include both `mcp_tools` and the native tools
|
|
18
|
-
the
|
|
18
|
+
the model needs to load.
|
|
19
19
|
|
|
20
20
|
## Resource snapshots
|
|
21
21
|
|
|
@@ -88,7 +88,7 @@ reconnection or configuration reload.
|
|
|
88
88
|
When a connected server reports a tool-list change, the extension invalidates its
|
|
89
89
|
memory and disk catalogs. The next discovery or activation fetches the current
|
|
90
90
|
list, including new or removed tools. Notifications don't replace active tool
|
|
91
|
-
definitions: the
|
|
91
|
+
definitions: the model must activate changed schemas again before use. Calls
|
|
92
92
|
validate the live catalog before execution and refuse removed or changed tools.
|
|
93
93
|
Disconnected, cache-only searches can't receive notifications and still use the
|
|
94
94
|
24-hour disk-cache expiry.
|
|
@@ -115,7 +115,7 @@ indentation and syntax highlighting. Explicit JSON resource MIME types (includin
|
|
|
115
115
|
`application/*+json`) and structured content identify JSON without guessing.
|
|
116
116
|
Other explicit MIME types stay plain text; unlabeled text is checked for JSON.
|
|
117
117
|
|
|
118
|
-
Formatting changes only the display, not the response sent to the
|
|
118
|
+
Formatting changes only the display, not the response sent to the model.
|
|
119
119
|
Invalid or truncated JSON stays plain text. Results that would exceed formatting
|
|
120
120
|
limits also stay plain text. Resource-link MIME types describe the linked content,
|
|
121
121
|
not the displayed link label. Supported images use the existing result display;
|
|
@@ -125,7 +125,8 @@ see [large results](troubleshooting.md#large-results) for size limits.
|
|
|
125
125
|
|
|
126
126
|
Only load configuration you trust. Server executables and secret commands run
|
|
127
127
|
with your user permissions; trusted project configuration can replace global
|
|
128
|
-
connections and settings.
|
|
128
|
+
connections and settings. See [project trust](#project-trust) for when a
|
|
129
|
+
project's `.mcp.json` loads.
|
|
129
130
|
|
|
130
131
|
Configuration imports require an explicit file, scope, selection, and final
|
|
131
132
|
confirmation. Import previews hide connection values; review the source file
|
|
@@ -148,3 +149,28 @@ Pi's tool restrictions to prevent discovery and resource operations. Already act
|
|
|
148
149
|
native tools have their own tool restrictions. Per-resource permission policies
|
|
149
150
|
aren't implemented. Prompt selection uses explicit user commands, not the
|
|
150
151
|
model-facing tool allowlist; disable the server to prevent prompt access.
|
|
152
|
+
|
|
153
|
+
## Project trust
|
|
154
|
+
|
|
155
|
+
A project's `.mcp.json` can start local commands, so it loads only after an
|
|
156
|
+
explicit trust decision for the folder. Pi asks for trust only in folders with Pi
|
|
157
|
+
project resources, such as `.pi/settings.json` or `.agents/skills`, and trusts
|
|
158
|
+
other folders implicitly. The extension doesn't rely on that implicit trust:
|
|
159
|
+
|
|
160
|
+
- **Folders with Pi project resources:** Pi's decision applies, including
|
|
161
|
+
`--approve` and session-only trust.
|
|
162
|
+
- **Other folders:** a saved decision for the folder or a parent folder applies.
|
|
163
|
+
Without one, Pi's `defaultProjectTrust` setting applies: `always` loads project
|
|
164
|
+
servers and `never` ignores them. With the default `ask`, interactive sessions
|
|
165
|
+
ask when a `.mcp.json` exists, and headless sessions ignore the file.
|
|
166
|
+
- **Untrusted folders:** `--no-approve` or a refusal in Pi always ignores project
|
|
167
|
+
servers.
|
|
168
|
+
|
|
169
|
+
Saved answers go to Pi's project trust store, so they also apply to Pi project
|
|
170
|
+
resources. Use Pi's `/trust` command to save or change a decision, then run
|
|
171
|
+
`/mcp reload`; MCP servers don't require a restart. In folders without Pi project
|
|
172
|
+
resources, `--approve` doesn't trust `.mcp.json`; save a decision instead.
|
|
173
|
+
|
|
174
|
+
Only session start and `/mcp reload` ask. Other configuration commands, such as
|
|
175
|
+
`/mcp add` and `/mcp import`, use the current decision. Untrusted project files
|
|
176
|
+
are neither read nor changed.
|
package/docs/commands.md
CHANGED
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
[Back to the README](../README.md)
|
|
4
4
|
|
|
5
|
-
These are commands **you run in Pi**, not tools the
|
|
6
|
-
manage servers, inspect capabilities, use prompts, and watch resource changes.
|
|
7
|
-
separate interface is documented in the [tool reference](tool-reference.md).
|
|
5
|
+
These are commands **you run in Pi**, not tools the model calls. Use them to
|
|
6
|
+
manage servers, inspect capabilities, use prompts, and watch resource changes.
|
|
7
|
+
The model's separate interface is documented in the [tool reference](tool-reference.md).
|
|
8
8
|
|
|
9
9
|
## Command reference
|
|
10
10
|
|
|
11
11
|
| Command | Purpose |
|
|
12
12
|
| --- | --- |
|
|
13
|
-
| `/mcp
|
|
13
|
+
| `/mcp` | Check server status, catalog tool counts, and tools loaded for the model. |
|
|
14
14
|
| `/mcp add --scope <scope> [options] <server> <url>` | Save an HTTP server without connecting. For stdio, use `<server> -- <command> [args...]`. |
|
|
15
15
|
| `/mcp remove --scope <scope> <server>` | Remove a definition from the selected scope, retaining credentials. |
|
|
16
16
|
| `/mcp import --scope <scope> <path>` | Preview and select servers from Claude/Cursor JSON or Codex TOML, then confirm a scoped import. |
|
|
@@ -33,11 +33,16 @@ See [Authentication](authentication.md) for login and logout procedures, and
|
|
|
33
33
|
|
|
34
34
|
## Inspect servers and tools
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
Use `/mcp` to check your setup or investigate a connection problem. It reports
|
|
37
|
+
whether each server is idle, connected, connecting, disabled, or in an error
|
|
38
|
+
state, along with catalog tool counts and tools loaded for the model.
|
|
39
|
+
|
|
40
|
+
Idle is normal: connections open on demand. A dash (`—`) means the catalog hasn't
|
|
41
|
+
been fetched, not that the server has no tools. **Loaded** counts tools currently
|
|
42
|
+
active for the model.
|
|
43
|
+
|
|
44
|
+
Checking status doesn't open connections or send information to the model.
|
|
45
|
+
The result stays in your transcript; run the command again for updated status.
|
|
41
46
|
|
|
42
47
|
Use `/mcp get <server>` to check the effective transport, protocol, filters,
|
|
43
48
|
and connection status without connecting or running secret commands. Connection
|
|
@@ -48,15 +53,14 @@ unavailable credential store is reported separately from missing tokens. Header
|
|
|
48
53
|
and stdio credentials are identified as externally managed; inspection never
|
|
49
54
|
executes them.
|
|
50
55
|
|
|
51
|
-
Use `/mcp tools <server>` to
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
context. This command requires an interactive UI.
|
|
56
|
+
Use `/mcp tools <server>` to find out what a server can do. It fetches the current
|
|
57
|
+
catalog so you can inspect tool descriptions, parameters, and required inputs.
|
|
58
|
+
Browsing respects your include and exclude filters and doesn't activate tools
|
|
59
|
+
or add their schemas to the model's context. This command requires an
|
|
60
|
+
interactive UI.
|
|
57
61
|
|
|
58
62
|
Refreshing a catalog doesn't replace active tool definitions. After a schema
|
|
59
|
-
change, ask the
|
|
63
|
+
change, ask the model to activate the exact tool again. See
|
|
60
64
|
[tool changes and caching](behavior.md#discovery-and-caching). Failed tool calls
|
|
61
65
|
aren't retried automatically; verify whether an interrupted operation completed
|
|
62
66
|
before trying again.
|
|
@@ -108,7 +112,7 @@ Both commands wait for active agent work to finish, then
|
|
|
108
112
|
[apply the configuration](configuration.md#apply-changes).
|
|
109
113
|
|
|
110
114
|
Disabling removes the server from discovery and deactivates its tools. Enabling
|
|
111
|
-
doesn't connect, authenticate, or load tools; ask the
|
|
115
|
+
doesn't connect, authenticate, or load tools; ask the model to discover the
|
|
112
116
|
capabilities you need.
|
|
113
117
|
|
|
114
118
|
## Add and remove servers
|
|
@@ -116,8 +120,9 @@ capabilities you need.
|
|
|
116
120
|
Both commands require an explicit `--scope global` or `--scope project`:
|
|
117
121
|
|
|
118
122
|
- **Global:** `~/.pi/agent/mcp.json`.
|
|
119
|
-
- **Project:** `.mcp.json` in the current
|
|
120
|
-
|
|
123
|
+
- **Project:** `.mcp.json` in the current
|
|
124
|
+
[trusted project](behavior.md#project-trust). Untrusted project files are
|
|
125
|
+
neither read nor changed.
|
|
121
126
|
|
|
122
127
|
Add an HTTP server by URL, or a stdio server after `--`:
|
|
123
128
|
|
|
@@ -190,7 +195,8 @@ automatically; no conversion file is needed:
|
|
|
190
195
|
```
|
|
191
196
|
|
|
192
197
|
The command requires an interactive TUI or RPC session and an explicit
|
|
193
|
-
`--scope global` or `--scope project`. Project scope requires a
|
|
198
|
+
`--scope global` or `--scope project`. Project scope requires a
|
|
199
|
+
[trusted project](behavior.md#project-trust).
|
|
194
200
|
Relative source paths resolve against Pi's current directory; `~/` is supported.
|
|
195
201
|
The path isn't evaluated by a shell, and no application settings are scanned.
|
|
196
202
|
|
|
@@ -282,7 +288,7 @@ streams. It never opens the URI as a file or generic URL.
|
|
|
282
288
|
An update marks the watch as changed (`↻`) and shows a UI notification. Repeated
|
|
283
289
|
updates coalesce into that marker until you unsubscribe. No content is fetched,
|
|
284
290
|
no model turn starts, and existing resource results remain unchanged. Ask the
|
|
285
|
-
|
|
291
|
+
model to read the resource for a new snapshot; unsubscribe and subscribe again
|
|
286
292
|
to reset the change marker.
|
|
287
293
|
|
|
288
294
|
Watches are memory-only, limited to 50 per server connection, and require an
|
package/docs/configuration.md
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
[Back to the README](../README.md)
|
|
4
4
|
|
|
5
|
-
You configure which servers the
|
|
6
|
-
`~/.pi/agent/mcp.json`, or `.mcp.json` in a
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
You configure which servers the model can access. Add connections to
|
|
6
|
+
`~/.pi/agent/mcp.json`, or `.mcp.json` in a
|
|
7
|
+
[trusted project](behavior.md#project-trust). For command-based setup, see
|
|
8
|
+
[Add and remove servers](commands.md#add-and-remove-servers). To reuse an
|
|
9
|
+
existing Claude/Cursor JSON or Codex TOML file, see
|
|
9
10
|
[Import server definitions](commands.md#import-server-definitions).
|
|
10
11
|
|
|
11
12
|
## Files and transports
|
|
@@ -16,8 +17,10 @@ MCP configuration standard. Live configuration must use JSON, not VS Code's
|
|
|
16
17
|
this format. `PI_CODING_AGENT_DIR` overrides the global Pi directory.
|
|
17
18
|
Project definitions replace same-named global definitions in full; fields and
|
|
18
19
|
filters aren't merged. Untrusted project definitions aren't loaded or edited.
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
Project servers need an explicit trust decision even in folders that Pi trusts
|
|
21
|
+
implicitly; see [project trust](behavior.md#project-trust). An explicitly named
|
|
22
|
+
import source is read as data for review; saving into project scope still
|
|
23
|
+
requires project trust.
|
|
21
24
|
|
|
22
25
|
```json
|
|
23
26
|
{
|
|
@@ -44,13 +47,24 @@ scope still requires project trust.
|
|
|
44
47
|
| `type` | Optional `stdio` or `http`. If omitted, inferred from `command` or `url`. A conflicting type is rejected. |
|
|
45
48
|
| `command`, `args` | Executable and arguments for a stdio server. No shell is used. |
|
|
46
49
|
| `cwd` | Working directory for stdio; defaults to Pi's current directory. Relative paths resolve there. |
|
|
47
|
-
| `env` |
|
|
50
|
+
| `env` | Environment variables for stdio, in addition to a minimal inherited set. |
|
|
48
51
|
| `url` | Streamable HTTP endpoint; mutually exclusive with `command`. |
|
|
49
52
|
| `headers` | HTTP request headers, including optional bearer authentication. |
|
|
50
53
|
|
|
51
54
|
Strings in `command`, `args`, `cwd`, `env`, `url`, and `headers` support `${VAR}`
|
|
52
55
|
interpolation. Missing variables prevent that server from connecting.
|
|
53
56
|
|
|
57
|
+
Stdio servers don't inherit Pi's environment. They receive only the MCP SDK's
|
|
58
|
+
default set (`HOME`, `LOGNAME`, `PATH`, `SHELL`, `TERM`, and `USER` on Unix, and
|
|
59
|
+
similar system variables on Windows) plus `env`. Pass other variables a server
|
|
60
|
+
needs explicitly, for example a custom browser location:
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
"env": {
|
|
64
|
+
"PLAYWRIGHT_BROWSERS_PATH": "${PLAYWRIGHT_BROWSERS_PATH}"
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
54
68
|
Only stdio and Streamable HTTP are supported. The extension rejects `type: "sse"`
|
|
55
69
|
and unsupported connection fields rather than silently changing their meaning.
|
|
56
70
|
|
|
@@ -119,7 +133,7 @@ server definition:
|
|
|
119
133
|
|
|
120
134
|
| Field | Purpose |
|
|
121
135
|
| --- | --- |
|
|
122
|
-
| `description` | Short capability description for the
|
|
136
|
+
| `description` | Short capability description for the model's server directory. |
|
|
123
137
|
| `oauthClientId` | Optional pre-registered public client ID. Supports `${ENV_VAR}` interpolation, not secret commands. |
|
|
124
138
|
| `oauthScopes` | Optional array of 1–100 unique OAuth scope tokens to request at login. Omitted scopes use SDK/server defaults. Values are literal, without interpolation. |
|
|
125
139
|
| `oauthCallbackPort` | Optional loopback callback port, from 1 to 65535. Defaults to `19847`. |
|
package/docs/tool-reference.md
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Model tool reference
|
|
2
2
|
|
|
3
3
|
[Back to the README](../README.md)
|
|
4
4
|
|
|
5
|
-
This page documents **the
|
|
6
|
-
calls the
|
|
5
|
+
This page documents **the model's interface**. The examples illustrate tool
|
|
6
|
+
calls the model makes; they aren't slash commands or JavaScript for you to
|
|
7
7
|
run. Describe your task in natural language. For operations you control directly,
|
|
8
8
|
see [Commands](commands.md).
|
|
9
9
|
|
|
10
10
|
The `mcp_tools` tool supports four mutually exclusive operations:
|
|
11
11
|
|
|
12
|
-
| Operation | What the
|
|
12
|
+
| Operation | What the model can do | What it doesn't do |
|
|
13
13
|
| --- | --- | --- |
|
|
14
14
|
| `query` | Discover tool, resource, and prompt metadata. | Read content or activate tools. |
|
|
15
15
|
| `activate` | Load full schemas for exact tool identifiers. | Invoke tools. |
|
|
16
16
|
| `read` | Fetch one resource as conversation context. | Activate tools or follow links automatically. |
|
|
17
17
|
| `complete` | Request server suggestions for a template variable. | Read resources, activate tools, or select a value. |
|
|
18
18
|
|
|
19
|
-
The
|
|
19
|
+
The model passes exactly one of `query`, `activate`, `read`, or `complete`.
|
|
20
20
|
The optional `kind`, `server`, and `limit` fields are query-only; reads and
|
|
21
21
|
completions carry their server inside their respective objects.
|
|
22
22
|
|
|
@@ -40,7 +40,7 @@ content type when supplied. Concrete resources and tools include exact next-call
|
|
|
40
40
|
arguments; templates include a read-call shape and variable names.
|
|
41
41
|
|
|
42
42
|
Prompt candidates show the owning server, name, description, argument metadata,
|
|
43
|
-
and a user-only command such as `/mcp prompt docs explain`. The
|
|
43
|
+
and a user-only command such as `/mcp prompt docs explain`. The model can
|
|
44
44
|
recommend this command but can't retrieve or run prompts through `mcp_tools`.
|
|
45
45
|
Only you can [select, preview, and use a prompt](commands.md#use-server-prompts).
|
|
46
46
|
|
|
@@ -62,7 +62,7 @@ mcp_tools({ activate: ["linear.list_teams", "linear.get_team"] })
|
|
|
62
62
|
|
|
63
63
|
Activation accepts 1–50 exact `server.tool` or `mcp__server__tool` identifiers,
|
|
64
64
|
ignores duplicates, and works without a prior search. Typos never activate fuzzy
|
|
65
|
-
matches: failures list nearby catalog names when available so the
|
|
65
|
+
matches: failures list nearby catalog names when available so the model can
|
|
66
66
|
retry with an exact identifier. Each identifier reports `loaded`, `already loaded`,
|
|
67
67
|
or `not loaded` with a reason. Partial success keeps the tools that loaded.
|
|
68
68
|
|
|
@@ -74,7 +74,7 @@ tool. There is no invocation proxy. Previously loaded tools remain available;
|
|
|
74
74
|
## Read resources as context
|
|
75
75
|
|
|
76
76
|
For a request such as “Use the authentication guide to explain this API,” the
|
|
77
|
-
|
|
77
|
+
model can discover and read relevant context:
|
|
78
78
|
|
|
79
79
|
```js
|
|
80
80
|
mcp_tools({ query: "authentication guide", kind: "resources" })
|
|
@@ -87,7 +87,7 @@ request, even for `file:` or `https:` URIs. There is no fallback when the server
|
|
|
87
87
|
can't read the URI. The server still controls which data it returns.
|
|
88
88
|
|
|
89
89
|
Tool-returned resource links include an exact `mcp_tools({read: ...})` call. The
|
|
90
|
-
|
|
90
|
+
model can read such links directly, without prior discovery or activation;
|
|
91
91
|
linked resources don't have to appear in the catalog.
|
|
92
92
|
|
|
93
93
|
Reading attaches content as the tool result itself, not as a second message. The
|
|
@@ -100,7 +100,7 @@ limits and private spill files.
|
|
|
100
100
|
|
|
101
101
|
Discovery also lists URI templates, such as `schema://tables/{table}`, without
|
|
102
102
|
enumerating every possible table. Templates have a `[template]` label, variable
|
|
103
|
-
names, and a read-call shape. The
|
|
103
|
+
names, and a read-call shape. The model supplies known argument values:
|
|
104
104
|
|
|
105
105
|
```js
|
|
106
106
|
mcp_tools({ query: "table schema", server: "warehouse", kind: "resources" })
|
|
@@ -117,7 +117,7 @@ The `read` object accepts either `uri` or `template` plus `arguments`, never bot
|
|
|
117
117
|
The selected server must advertise the exact template. The official SDK expands
|
|
118
118
|
strings or string arrays into a concrete URI, then reads it through that same
|
|
119
119
|
server. Template variables aren't an input schema: no required fields or allowed
|
|
120
|
-
values are inferred. The
|
|
120
|
+
values are inferred. The model should use values from your request or prior
|
|
121
121
|
results and ask you when a needed value is unknown rather than inventing an
|
|
122
122
|
identifier.
|
|
123
123
|
|
|
@@ -128,7 +128,7 @@ content; see [result display](behavior.md#result-display).
|
|
|
128
128
|
|
|
129
129
|
## Complete resource arguments
|
|
130
130
|
|
|
131
|
-
The
|
|
131
|
+
The model can ask a server for suggested values for one advertised template
|
|
132
132
|
variable:
|
|
133
133
|
|
|
134
134
|
```js
|
|
@@ -142,7 +142,7 @@ mcp_tools({
|
|
|
142
142
|
```
|
|
143
143
|
|
|
144
144
|
`value` is the current prefix and can be empty. For dependent suggestions, the
|
|
145
|
-
|
|
145
|
+
model can add `arguments: { knownVariable: "value" }` inside `complete`.
|
|
146
146
|
These context values must be strings, not arrays. The server must advertise
|
|
147
147
|
completion support and the exact template; the variable must occur in that
|
|
148
148
|
template.
|
package/docs/troubleshooting.md
CHANGED
|
@@ -27,16 +27,16 @@ unavailable server isn't an empty catalog.
|
|
|
27
27
|
| `connection_failed` | Server executable, working directory, endpoint, network, and TLS configuration. |
|
|
28
28
|
| `timeout` | Server responsiveness and the applicable request, secret-command, or OAuth time limit. |
|
|
29
29
|
| `protocol_error` | Server compatibility and the `protocol` setting. |
|
|
30
|
-
| `tool_changed` | Check server filters and ask the
|
|
30
|
+
| `tool_changed` | Check server filters and ask the model to activate the exact tool again for its current schema. Run `/mcp reload` if connection configuration changed. |
|
|
31
31
|
| `tool_error` | The server's tool result and inputs; verify the outcome before retrying. |
|
|
32
|
-
| `resource_invalid` | The
|
|
32
|
+
| `resource_invalid` | The model needs an exact absolute resource URI from discovery or a tool-returned link. |
|
|
33
33
|
| `resource_not_found` | Refresh resource metadata or obtain a new link. |
|
|
34
|
-
| `resources_unsupported` | Ask the
|
|
35
|
-
| `completions_unsupported` | Supply known template values; the
|
|
36
|
-
| `completion_invalid` | The
|
|
37
|
-
| `subscriptions_unsupported` | Choose a server with subscription support, or ask the
|
|
34
|
+
| `resources_unsupported` | Ask the model to use the server's tools instead, or choose a resource-capable server. |
|
|
35
|
+
| `completions_unsupported` | Supply known template values; the model should ask you if a value is missing. |
|
|
36
|
+
| `completion_invalid` | The model needs an advertised template variable and a string prefix. |
|
|
37
|
+
| `subscriptions_unsupported` | Choose a server with subscription support, or ask the model to read when needed. |
|
|
38
38
|
| `subscription_limit` | Remove a watch before adding another; the limit is 50 per connection. |
|
|
39
|
-
| `catalog_changed` | Ask the
|
|
39
|
+
| `catalog_changed` | Ask the model to retry discovery after the server catalog settles. |
|
|
40
40
|
| `oauth_failed` | An unclassified OAuth failure. Check the service's requirements and `/mcp get <server>` for the client type, scopes, and callback URL. Only public/PKCE clients are supported, not clients requiring a secret. |
|
|
41
41
|
| `oauth_client_required` | The server doesn't support dynamic registration. Configure `oauthClientId` for a registered public/PKCE client and register the exact callback URL. Reload, then log in again. |
|
|
42
42
|
| `oauth_registration_rejected` | The server rejected dynamic registration. Check public/native client eligibility and the callback URL, or configure an approved public client ID. |
|
|
@@ -69,6 +69,21 @@ remain visible as content, even when the tool reports an error; they aren't
|
|
|
69
69
|
sanitized transport diagnostics. Tool-call failures aren't replayed automatically;
|
|
70
70
|
verify the outcome before retrying.
|
|
71
71
|
|
|
72
|
+
## Missing project servers
|
|
73
|
+
|
|
74
|
+
A project's `.mcp.json` loads only after an explicit trust decision, even in
|
|
75
|
+
folders that Pi otherwise trusts implicitly. Headless sessions ignore it when no
|
|
76
|
+
decision exists. Run Pi's `/trust` command to save a decision, then run
|
|
77
|
+
`/mcp reload`. See [project trust](behavior.md#project-trust).
|
|
78
|
+
|
|
79
|
+
## Missing server dependencies
|
|
80
|
+
|
|
81
|
+
If a stdio server reports a missing browser, SDK, credential, or configuration
|
|
82
|
+
file that works in your shell, it probably reads an environment variable that
|
|
83
|
+
it doesn't receive. Servers don't inherit Pi's environment; pass the variable
|
|
84
|
+
through `env`, for example `PLAYWRIGHT_BROWSERS_PATH`. See
|
|
85
|
+
[files and transports](configuration.md#files-and-transports).
|
|
86
|
+
|
|
72
87
|
## Large results
|
|
73
88
|
|
|
74
89
|
Text output is limited to 2,000 lines or 50 KiB, including resource reads and
|