Skip to content

Commit b889cdf

Browse files
committed
Agents pane: CLI-only MCP, yaak mcp --http, and plugin deprecation
The agent story is one sentence: install the Yaak CLI, and every agent talks to it. The app no longer hosts an MCP server; `yaak mcp` serves stdio and `yaak mcp --http` serves HTTP with a bearer token for agents that cannot run the host's CLI. Settings > Agents is the picker, a CLI status line, and two command blocks (add the MCP server, install the skill), each marked done when the agent's config and skills directory already have it. A banner appears when the deprecated @yaak/mcp-server plugin is installed. The plugin API reads the registry's new `deprecated` note; Discover hides deprecated plugins and the Installed tab shows the note with an Uninstall button. The mcp-server plugin carries the note, a reworded toast, and a README that points at `yaak mcp`.
1 parent 9b37150 commit b889cdf

32 files changed

Lines changed: 834 additions & 521 deletions

File tree

‎apps/yaak-client/components/Settings/Settings.tsx‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,6 @@ export default function Settings({ tab, hide }: Props) {
123123
<CountBadge count={settings.clientCertificates.length} />
124124
) : value === TAB_PLUGINS ? (
125125
<CountBadge count={plugins.filter((p) => p.source !== "bundled").length} />
126-
) : value === TAB_AGENTS && settings.mcpServerEnabled ? (
127-
<CountBadge count />
128126
) : value === TAB_PROXY && settings.proxy?.type === "enabled" ? (
129127
<CountBadge count />
130128
) : value === TAB_LICENSE && licenseCheck.check.data?.status === "personal_use" ? (
Lines changed: 88 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -1,145 +1,72 @@
1-
import { useQuery } from "@tanstack/react-query";
2-
import { settingsAtom } from "@yaakapp-internal/models";
1+
import { useQuery, useQueryClient } from "@tanstack/react-query";
32
import { platform } from "@yaakapp-internal/platform";
4-
import { Heading, Icon, InlineCode, VStack } from "@yaakapp-internal/ui";
5-
import type { AppMetaData } from "@yaakapp-internal/rpc-schema";
6-
import { useAtomValue } from "jotai";
3+
import type { AgentSetupStatus, AppMetaData } from "@yaakapp-internal/rpc-schema";
4+
import { Banner, Heading, Icon, InlineCode, VStack } from "@yaakapp-internal/ui";
5+
import { useEffect } from "react";
76
import { useKeyValue } from "../../hooks/useKeyValue";
8-
import { appInfo } from "../../lib/appInfo";
7+
import { usePluginInfos } from "../../hooks/usePluginInfo";
98
import {
109
AGENT_CLIENTS,
1110
type AgentClient,
12-
type AgentSetup,
13-
appSetup,
1411
cliSetup,
12+
skillInstallCommand,
1513
} from "../../lib/agentSetup";
14+
import { appInfo } from "../../lib/appInfo";
1615
import { rpc } from "../../lib/rpc";
17-
import { CopyIconButton } from "../CopyIconButton";
18-
import { Button } from "../core/Button";
19-
import { Editor } from "../core/Editor/LazyEditor";
20-
import { IconButton } from "../core/IconButton";
16+
import { Link } from "../core/Link";
2117
import { SegmentedControl } from "../core/SegmentedControl";
2218
import {
23-
ModelSettingRowBoolean,
24-
SettingRow,
25-
SettingValue,
19+
SettingCommand,
20+
SettingSnippet,
2621
SettingsList,
2722
SettingsSection,
2823
} from "../core/SettingRow";
24+
import { DeprecatedPluginBanner } from "./SettingsPlugins";
2925

30-
const MCP_URL = "http://127.0.0.1:64343/mcp";
3126
const CLI_INSTALL_COMMAND = "npm install -g @yaakapp/cli";
32-
const SKILL_INSTALL_COMMAND = "yaak agent install";
27+
const MCP_SERVER_PLUGIN = "@yaak/mcp-server";
3328

3429
export function SettingsAgents() {
35-
const settings = useAtomValue(settingsAtom);
36-
const { value: token } = useKeyValue<string | null>({
37-
namespace: "no_sync",
38-
key: "mcp_server_token",
39-
fallback: null,
40-
});
30+
const queryClient = useQueryClient();
4131
const { value: storedClient, set: setClient } = useKeyValue<AgentClient>({
4232
key: "agents_setup_client",
4333
fallback: "claude_code",
4434
});
4535
const client = AGENT_CLIENTS.find((c) => c.value === storedClient)?.value ?? "claude_code";
36+
const clientLabel = AGENT_CLIENTS.find((c) => c.value === client)?.label ?? "your agent";
4637
const cliVersion = useQuery({
4738
queryKey: ["cli_version"],
4839
queryFn: async () => (await rpc<AppMetaData>("cmd_metadata")).cliVersion,
4940
initialData: appInfo.cliVersion,
5041
});
42+
const setupStatus = useQuery({
43+
queryKey: ["agent_setup_status", client],
44+
queryFn: () => rpc<AgentSetupStatus>("cmd_agent_setup_status", { agent: client }),
45+
});
46+
const mcpServerPlugin = usePluginInfos().find(({ info }) => info.name === MCP_SERVER_PLUGIN);
47+
48+
useEffect(() => {
49+
return platform.window.onFocusChanged((focused) => {
50+
if (!focused) return;
51+
void queryClient.invalidateQueries({ queryKey: ["cli_version"] });
52+
void queryClient.invalidateQueries({ queryKey: ["agent_setup_status"] });
53+
});
54+
}, [queryClient]);
55+
56+
const cliInstalled = cliVersion.data != null;
57+
const cli = cliSetup(client);
5158

5259
return (
5360
<VStack space={1.5} className="mb-4">
5461
<div className="mb-3">
5562
<Heading>Agents</Heading>
5663
<p className="text-text-subtle">
57-
Connect AI coding agents like Claude Code and Cursor to Yaak, so they can read, edit, and
58-
send your requests.
64+
Connect AI coding agents like Claude Code and Cursor to Yaak.
5965
</p>
6066
</div>
61-
<SettingsList className="space-y-8">
62-
<SettingsSection
63-
title="Yaak CLI"
64-
description="Lets agents use Yaak from the command line, even with the app closed."
65-
>
66-
<SettingRow
67-
title="Status"
68-
description={
69-
cliVersion.data == null
70-
? "The Yaak CLI is not installed."
71-
: `Yaak CLI ${cliVersion.data} is installed.`
72-
}
73-
controlClassName="gap-2"
74-
>
75-
<IconButton
76-
size="sm"
77-
icon="refresh"
78-
title="Check again"
79-
spin={cliVersion.isFetching}
80-
onClick={() => cliVersion.refetch()}
81-
/>
82-
{cliVersion.data == null && (
83-
<Button
84-
variant="border"
85-
color="secondary"
86-
size="sm"
87-
onClick={() => platform.openUrl("https://yaak.app/docs/cli")}
88-
rightSlot={<Icon icon="external_link" />}
89-
>
90-
Install CLI
91-
</Button>
92-
)}
93-
</SettingRow>
94-
{cliVersion.data == null ? (
95-
<SettingRow title="Install" description="Install it with npm.">
96-
<SettingValue value={CLI_INSTALL_COMMAND} />
97-
</SettingRow>
98-
) : (
99-
<SettingRow
100-
title="Agent skill"
101-
description={
102-
<>
103-
Teach Claude Code, Cursor, Codex, and opencode to drive the{" "}
104-
<InlineCode>yaak</InlineCode> command, wherever they're installed.
105-
</>
106-
}
107-
>
108-
<SettingValue value={SKILL_INSTALL_COMMAND} />
109-
</SettingRow>
110-
)}
111-
</SettingsSection>
112-
113-
<SettingsSection
114-
title="MCP server in the app"
115-
description="For agents that connect over HTTP, or to act on the workspaces open in Yaak."
116-
>
117-
<ModelSettingRowBoolean
118-
model={settings}
119-
modelKey="mcpServerEnabled"
120-
title="Enable MCP server"
121-
description={
122-
<>
123-
Serve Yaak's tools at <InlineCode>{MCP_URL}</InlineCode> while Yaak is open.
124-
</>
125-
}
126-
/>
127-
{settings.mcpServerEnabled && token != null && (
128-
<SettingRow
129-
title="Token"
130-
description="Agents send this as a bearer token."
131-
controlClassName="min-w-0 max-w-[min(24rem,40vw)] gap-2"
132-
>
133-
<SettingValue value={token} />
134-
</SettingRow>
135-
)}
136-
</SettingsSection>
137-
138-
<SettingsSection
139-
title="Connect an agent"
140-
description="Pick your agent or editor to see how to add Yaak's MCP tools to it."
141-
>
142-
<div className="py-4 border-b border-border-subtle">
67+
<SettingsList>
68+
<SettingsSection title={null}>
69+
<div className="pb-4 border-b border-border-subtle">
14370
<SegmentedControl
14471
name="agents_setup_client"
14572
label="Agent"
@@ -149,59 +76,65 @@ export function SettingsAgents() {
14976
options={AGENT_CLIENTS}
15077
/>
15178
</div>
152-
<SetupRow
153-
title="Through the Yaak CLI"
79+
{cliInstalled ? (
80+
<div className="flex items-center gap-2 py-3 text-sm text-text-subtle border-b border-border-subtle">
81+
<Icon icon="check" size="sm" color="success" />
82+
<span>
83+
Yaak CLI <span className="text-text">{cliVersion.data}</span> is installed.
84+
</span>
85+
</div>
86+
) : (
87+
<div className="py-4 border-b border-border-subtle">
88+
<Banner color="info">
89+
<div className="flex items-center gap-2 text text-text">
90+
<Icon icon="square_terminal" color="info" />
91+
Install the Yaak CLI first
92+
</div>
93+
<p className="mt-1 text-sm text-text-subtle">
94+
Agents launch it to reach Yaak, even with the app closed.
95+
</p>
96+
<SettingSnippet className="mt-3" language="shell" snippet={CLI_INSTALL_COMMAND} />
97+
<div className="mt-3 mb-1 flex items-center gap-4 text-sm">
98+
<Link href="https://yaak.app/docs/cli">Docs</Link>
99+
<span className="text-text-subtlest">
100+
Checks again when you come back to Yaak.
101+
</span>
102+
</div>
103+
</Banner>
104+
</div>
105+
)}
106+
{mcpServerPlugin != null && (
107+
<div className="py-4 border-b border-border-subtle">
108+
<DeprecatedPluginBanner
109+
plugin={mcpServerPlugin.plugin}
110+
name={mcpServerPlugin.info.displayName}
111+
>
112+
The two steps below replace it. Uninstall it once your agent is connected.
113+
</DeprecatedPluginBanner>
114+
</div>
115+
)}
116+
<SettingCommand
117+
title="Add the MCP server"
118+
description={cli.where}
119+
snippet={cli.snippet}
120+
language={cli.language}
121+
disabled={!cliInstalled}
122+
done={setupStatus.data?.mcpServer ? "Added" : null}
123+
/>
124+
<SettingCommand
125+
title="Install the skill"
154126
description={
155-
cliVersion.data == null
156-
? "Recommended. Install the Yaak CLI above first."
157-
: `Recommended. ${cliSetup(client).where}`
127+
<>
128+
Lets {clientLabel} run the <InlineCode>yaak</InlineCode> command directly.
129+
</>
158130
}
159-
setup={cliSetup(client)}
131+
snippet={skillInstallCommand(client)}
132+
language="shell"
133+
disabled={!cliInstalled}
134+
done={setupStatus.data?.skill ? "Installed" : null}
160135
/>
161-
{settings.mcpServerEnabled && token != null ? (
162-
<SetupRow
163-
title="Through the app"
164-
description={appSetup(client, MCP_URL, token).where}
165-
setup={appSetup(client, MCP_URL, token)}
166-
/>
167-
) : (
168-
<SettingRow
169-
title="Through the app"
170-
description="Turn on the MCP server above to connect this way."
171-
>
172-
<span />
173-
</SettingRow>
174-
)}
175136
</SettingsSection>
176137
</SettingsList>
177138
</VStack>
178139
);
179140
}
180-
181-
function SetupRow({
182-
title,
183-
description,
184-
setup,
185-
}: {
186-
title: string;
187-
description: string;
188-
setup: AgentSetup;
189-
}) {
190-
return (
191-
<div className="py-4 border-b border-border-subtle">
192-
<div className="text text-text">{title}</div>
193-
<div className="mt-1 text-sm text-text-subtle">{description}</div>
194-
<Editor
195-
readOnly
196-
hideGutter
197-
wrapLines
198-
heightMode="auto"
199-
stateKey={null}
200-
language={setup.language}
201-
defaultValue={setup.snippet}
202-
className="mt-3 border border-border-subtle rounded-md px-2"
203-
actions={<CopyIconButton size="sm" variant="border" text={setup.snippet} title="Copy setup" />}
204-
/>
205-
</div>
206-
);
207-
}

0 commit comments

Comments
 (0)