1- import { v1 } from "@docker/extension-api-client-types" ;
2- import { getUser , readFileInPromptsVolume } from "./FileWatcher" ;
3-
41export const POLL_INTERVAL = 1000 * 30 ;
52export const MCP_POLICY_NAME = 'MCP=*' ;
63export const DD_BUILD_WITH_SECRET_SUPPORT = 184396 ;
74export const CATALOG_URL = 'https://raw.githubusercontent.com/docker/labs-ai-tools-for-devs/refs/heads/main/prompts/catalog.yaml'
8- export const DOCKER_MCP_CONFIG = {
9- "command" : "docker" ,
10- "args" : [
11- "run" ,
12- "-i" ,
13- "--rm" ,
14- "alpine/socat" ,
15- "STDIO" ,
16- "TCP:host.docker.internal:8811"
17- ]
18- }
19- export type MCPClient = {
20- name : string ;
21- url : string ;
22- readFile : ( client : v1 . DockerDesktopClient ) => Promise < { content : string | null | undefined , path : string } > ;
23- connect : ( client : v1 . DockerDesktopClient ) => Promise < void > ;
24- disconnect : ( client : v1 . DockerDesktopClient ) => Promise < void > ;
25- validateConfig : ( content : string ) => boolean ;
26- }
5+
276export const getUnsupportedSecretMessage = ( ddVersion : { version : string , build : number } ) => {
287 return `Secret support is not available in this version of Docker Desktop. You are on version ${ ddVersion . version } , but the minimum required version is 4.40.0.`
298}
30- export const SUPPORTED_MCP_CLIENTS : MCPClient [ ] = [
31- {
32- name : 'Claude Desktop' ,
33- url : 'https://claude.ai/download' ,
34- readFile : async ( client : v1 . DockerDesktopClient ) => {
35- const platform = client . host . platform
36- let path = ''
37- switch ( platform ) {
38- case 'darwin' :
39- path = '/Users/$USER/Library/Application Support/Claude/claude_desktop_config.json'
40- break ;
41- case 'linux' :
42- path = '/home/$USER/.config/claude/claude_desktop_config.json'
43- break ;
44- case 'win32' :
45- path = '%APPDATA%\\Claude\\claude_desktop_config.json'
46- break ;
47- default :
48- throw new Error ( 'Unsupported platform: ' + platform )
49- }
50- const user = await getUser ( client )
51- path = path . replace ( '$USER' , user )
52- try {
53- const result = await client . docker . cli . exec ( 'run' , [ '--rm' , '--mount' , `type=bind,source="${ path } ",target=/config.json` , 'alpine:latest' , 'sh' , '-c' , `"cat /config.json"` ] )
54- return { content : result . stdout || undefined , path : path } ;
55- } catch ( e ) {
56- return { content : null , path : path } ;
57- }
58- } ,
59- connect : async ( client : v1 . DockerDesktopClient ) => {
60- const platform = client . host . platform
61- let path = ''
62- switch ( platform ) {
63- case 'darwin' :
64- path = '/Users/$USER/Library/Application Support/Claude/'
65- break ;
66- case 'linux' :
67- path = '/home/$USER/.config/claude/'
68- break ;
69- case 'win32' :
70- path = '%APPDATA%\\Claude\\'
71- break ;
72- default :
73- throw new Error ( 'Unsupported platform: ' + platform )
74- }
75- const user = await getUser ( client )
76- path = path . replace ( '$USER' , user )
77- let payload = {
78- mcpServers : {
79- mcp_docker : DOCKER_MCP_CONFIG
80- }
81- }
82- try {
83- const result = await client . docker . cli . exec ( 'run' , [ '--rm' , '--mount' , `type=bind,source="${ path } ",target=/claude_desktop_config` , 'alpine:latest' , 'sh' , '-c' , `"cat /claude_desktop_config/claude_desktop_config.json"` ] )
84- if ( result . stdout ) {
85- payload = JSON . parse ( result . stdout )
86- payload . mcpServers . mcp_docker = DOCKER_MCP_CONFIG
87- }
88- } catch ( e ) {
89- // No config or malformed config found, overwrite it
90- }
91- try {
92- await client . docker . cli . exec ( 'run' , [ '--rm' , '--mount' , `type=bind,source="${ path } ",target=/claude_desktop_config` , '--workdir' , '/claude_desktop_config' , 'vonwig/function_write_files:latest' , `'${ JSON . stringify ( { files : [ { path : 'claude_desktop_config.json' , content : JSON . stringify ( payload ) } ] } ) } '` ] )
93- } catch ( e ) {
94- client . desktopUI . toast . error ( ( e as any ) . stderr )
95- }
96- } ,
97- disconnect : async ( client : v1 . DockerDesktopClient ) => {
98- const platform = client . host . platform
99- let path = ''
100- switch ( platform ) {
101- case 'darwin' :
102- path = '/Users/$USER/Library/Application Support/Claude/'
103- break ;
104- case 'linux' :
105- path = '/home/$USER/.config/claude/'
106- break ;
107- case 'win32' :
108- path = '%APPDATA%\\Claude\\'
109- break ;
110- default :
111- throw new Error ( 'Unsupported platform: ' + platform )
112- }
113- const user = await getUser ( client )
114- path = path . replace ( '$USER' , user )
115- try {
116- // This method is only called after the config has been validated, so we can safely assume it's a valid config.
117- const previousConfig = JSON . parse ( ( await client . docker . cli . exec ( 'run' , [ '--rm' , '--mount' , `type=bind,source="${ path } ",target=/claude_desktop_config` , '--workdir' , '/claude_desktop_config' , 'alpine:latest' , 'sh' , '-c' , `"cat /claude_desktop_config/claude_desktop_config.json"` ] ) ) . stdout || '{}' )
118- const newConfig = { ...previousConfig }
119- delete newConfig . mcpServers . mcp_docker
120- await client . docker . cli . exec ( 'run' , [ '--rm' , '--mount' , `type=bind,source="${ path } ",target=/claude_desktop_config` , '--workdir' , '/claude_desktop_config' , 'vonwig/function_write_files:latest' , `'${ JSON . stringify ( { files : [ { path : 'claude_desktop_config.json' , content : JSON . stringify ( newConfig ) } ] } ) } '` ] )
121- } catch ( e ) {
122- client . desktopUI . toast . error ( ( e as any ) . stderr )
123- }
124- } ,
125- validateConfig : ( content : string ) => {
126- const config = JSON . parse ( content )
127- return Object . keys ( config . mcpServers ) . some ( key => key . includes ( 'mcp_docker' ) )
128- }
129- }
130- ]
9+
10+ export const DOCKER_MCP_COMMAND = 'docker run -i --rm alpine/socat STDIO TCP:host.docker.internal:8811'
0 commit comments