* feat(acp): add reusable MCP connections - Store named Streamable HTTP connections separately from model providers - Keep bearer tokens in the credential manager and resolve them per ACP session - Add localized settings, validation, documentation, and focused coverage * test(acp): harden MCP connection workflow - Label credential inputs and confirm destructive connection removal - Exercise MCP server delivery through an in-memory ACP session - Extend the browser smoke test to cover accessible input and confirmation flows * fix(acp): validate MCP connection lifecycle - Keep non-browser storage initialization in memory and restore the German model copy - Reject persisted name collisions and invalid draft IDs - Preserve connections on credential failures and require credentials before enablement
54 lines
1.7 KiB
TypeScript
54 lines
1.7 KiB
TypeScript
import {
|
|
AgentSideConnection,
|
|
ClientSideConnection,
|
|
PROTOCOL_VERSION,
|
|
type Agent,
|
|
type Client,
|
|
type McpServer,
|
|
type NewSessionRequest
|
|
} from '@agentclientprotocol/sdk'
|
|
|
|
import { buildACPMCPServers } from '@/app/integrations/mcp'
|
|
|
|
function pairedStreams() {
|
|
const clientToAgent = new TransformStream()
|
|
const agentToClient = new TransformStream()
|
|
return {
|
|
client: { writable: clientToAgent.writable, readable: agentToClient.readable },
|
|
agent: { writable: agentToClient.writable, readable: clientToAgent.readable }
|
|
}
|
|
}
|
|
|
|
export async function captureACPSessionMCPServers(): Promise<McpServer[]> {
|
|
const streams = pairedStreams()
|
|
let received: NewSessionRequest | null = null
|
|
const client: Client = {
|
|
requestPermission: async () => ({ outcome: { outcome: 'cancelled' } }),
|
|
sessionUpdate: async () => undefined
|
|
}
|
|
const agent: Agent = {
|
|
initialize: async () => ({
|
|
protocolVersion: PROTOCOL_VERSION,
|
|
agentCapabilities: { loadSession: false }
|
|
}),
|
|
newSession: async (params) => {
|
|
received = params
|
|
return { sessionId: 'smoke-session' }
|
|
},
|
|
authenticate: async () => ({}),
|
|
prompt: async () => ({ stopReason: 'end_turn' }),
|
|
cancel: async () => undefined
|
|
}
|
|
|
|
const agentConnection = new AgentSideConnection(() => agent, streams.agent)
|
|
const connection = new ClientSideConnection(() => client, streams.client)
|
|
await connection.initialize({ protocolVersion: PROTOCOL_VERSION, clientCapabilities: {} })
|
|
await connection.newSession({
|
|
cwd: '/tmp',
|
|
mcpServers: await buildACPMCPServers({ authorizationToken: 'built-in-token' })
|
|
})
|
|
if (!received) throw new Error('ACP agent did not receive session configuration')
|
|
void agentConnection
|
|
return received.mcpServers
|
|
}
|