Remove MCP sampling support (#10087)

Co-authored-by: Douwe M Osinga <douwe@sidewalklabs.com>
Co-authored-by: Lifei Zhou <lifei@squareup.com>
This commit is contained in:
Douwe Osinga
2026-06-30 21:53:44 -04:00
committed by GitHub
parent c8971fe5fb
commit 66ce9a6beb
25 changed files with 144 additions and 345 deletions
@@ -51,8 +51,6 @@ import {
McpAppToolInputPartial,
DimensionLayout,
OnDisplayModeChange,
SamplingCreateMessageParams,
SamplingCreateMessageResponse,
} from './types';
import {
useDisplayMode,
@@ -676,13 +674,6 @@ export default function McpAppRenderer({
const [containerWidth, setContainerWidth] = useState<number>(0);
const [containerHeight, setContainerHeight] = useState<number>(0);
const [apiHost, setApiHost] = useState<string | null>(null);
const [secretKey, setSecretKey] = useState<string | null>(null);
useEffect(() => {
window.electron.getGoosedHostPort().then(setApiHost);
window.electron.getSecretKey().then(setSecretKey);
}, []);
// Fetch the resource from the extension to get HTML and metadata (CSP, permissions, etc.).
// If cachedHtml is provided we show it immediately; the fetch updates metadata and
@@ -933,38 +924,12 @@ export default function McpAppRenderer({
const handleFallbackRequest = useCallback(
async (request: JSONRPCRequest, _extra: RequestHandlerExtra) => {
if (request.method === 'sampling/createMessage') {
if (!sessionId || !apiHost || !secretKey) {
throw new Error('Session not initialized for sampling request');
}
const { messages, systemPrompt, maxTokens } =
request.params as unknown as SamplingCreateMessageParams;
const response = await fetch(`${apiHost}/sessions/${sessionId}/sampling/message`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Secret-Key': secretKey,
},
body: JSON.stringify({
messages: messages.map((m) => ({
role: m.role,
content: m.content,
})),
systemPrompt,
maxTokens,
}),
});
if (!response.ok) {
throw new Error(`Sampling request failed: ${response.statusText}`);
}
return (await response.json()) as SamplingCreateMessageResponse;
}
return {
status: 'error' as const,
message: `Unhandled JSON-RPC method: ${request.method ?? '<unknown>'}`,
};
},
[sessionId, apiHost, secretKey]
[]
);
const handleError = useCallback((err: Error) => {
@@ -41,21 +41,3 @@ export type McpAppToolCancelled = McpUiToolCancelledNotification['params'];
* host-side controls or app-initiated `ui/request-display-mode` changes.
*/
export type OnDisplayModeChange = (mode: GooseDisplayMode) => void;
export type SamplingMessage = {
role: 'user' | 'assistant';
content: { type: 'text'; text: string } | { type: 'image'; data: string; mimeType: string };
};
export type SamplingCreateMessageParams = {
messages: SamplingMessage[];
systemPrompt?: string;
maxTokens?: number;
};
export type SamplingCreateMessageResponse = {
model: string;
stopReason: string;
role: 'assistant';
content: { type: 'text'; text: string };
};
+25 -1
View File
@@ -1,12 +1,13 @@
import { useCallback, useEffect, useRef, useState } from 'react';
import { MainPanelLayout } from '../Layout/MainPanelLayout';
import { Button } from '../ui/button';
import { Download, Play, Upload } from 'lucide-react';
import { AlertTriangle, Download, Play, Upload } from 'lucide-react';
import type { GooseApp } from '../../types/apps';
import { exportMcpApp, importMcpApp, listMcpApps } from '../../acp/mcp-apps';
import { useChatContext } from '../../contexts/ChatContext';
import { formatAppName } from '../../utils/conversionUtils';
import { errorMessage } from '../../utils/conversionUtils';
import { isRetiredGooseChatApp } from '../../utils/retiredApps';
import { defineMessages, useIntl } from '../../i18n';
const i18n = defineMessages({
@@ -52,6 +53,14 @@ const i18n = defineMessages({
id: 'appsView.launch',
defaultMessage: 'Launch',
},
retiredChatApp: {
id: 'appsView.retiredChatApp',
defaultMessage: 'Chat app retired',
},
retiredChatAppDetail: {
id: 'appsView.retiredChatAppDetail',
defaultMessage: 'We removed this feature because MCP sampling is no longer supported.',
},
});
const GridLayout = ({ children }: { children: React.ReactNode }) => {
@@ -272,11 +281,25 @@ export default function AppsView() {
<GridLayout>
{apps.map((app) => {
const isCustomApp = app.mcpServers?.includes('apps') ?? false;
const retiredChatApp = isRetiredGooseChatApp(app);
return (
<div
key={`${app.uri}-${app.mcpServers?.join(',')}`}
className="flex flex-col p-4 border rounded-lg hover:border-border-primary transition-colors"
>
{retiredChatApp && (
<div className="mb-3 flex items-start gap-2 rounded border border-amber-300 bg-amber-50 px-3 py-2 text-sm text-amber-900 dark:border-amber-700 dark:bg-amber-950 dark:text-amber-100">
<AlertTriangle className="mt-0.5 h-4 w-4 shrink-0" />
<div>
<div className="font-medium">
{intl.formatMessage(i18n.retiredChatApp)}
</div>
<p className="mt-1 text-xs leading-5">
{intl.formatMessage(i18n.retiredChatAppDetail)}
</p>
</div>
</div>
)}
<div className="flex-1 mb-4">
<h3 className="font-medium text-text-primary mb-2">
{formatAppName(app.name)}
@@ -297,6 +320,7 @@ export default function AppsView() {
variant="default"
size="sm"
onClick={() => handleLaunchApp(app)}
disabled={retiredChatApp}
className="flex items-center gap-2 flex-1"
>
<Play className="h-4 w-4" />