-
Notifications
You must be signed in to change notification settings - Fork 843
Expose a Dagger module as an MCP server #9935
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
i'd love to see the stderr output with |
cmd/dagger/mcp.go
Outdated
| }, | ||
| } | ||
|
|
||
| // dagger -m github.com/org/repo mcp key1=val1 key2=val2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what do you see these keys and values being passed to? are they module-level flags?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My bad, this is more of a TODO of how to handle module constructors. Forgot to mention it in the description.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if it's possible they should retain the syntax of call, like --module-constructor-key=value
|
@cwlbraa Just want to clarify that this @grouville and I are finishing a barebones cli to be able to easily test this with an LLM. Will update the description. Currently, the official mcp-go client doesn't forward os.Stderr and the upstream change may need some UX debate, but in my fork I set "cmd.Stderr = os.Stderr" in the mcp-go client so that our testing cli does show --progress plain with the dagger operations visible. It just gets in the way of the interactiveness (the prompt ">" is lost when there's stderr output). Anyway this is for the testing mcp client, but we need a general solution. |
it's client specific, but claude desktop for example has pretty detailed debugging instructions and i'm curious if
agreed this feels like kinda a bad idea, something we should leave to docker lol |
|
So |
|
@tiborvass how does the dynamic tool support actually work? IIUC I can only start |
|
@marcosnils My bad, the terminology is confusing. What we meant by dynamic is that prior to calling a function that returns a What you are referring to is also justified being called dynamic and I believe it would require a "load module" function exposed in the LLM Env API. But note that this also suffers from the same problem that apart from Goose, nothing handles tools list update. |
235fdda to
cd852d6
Compare
db39d87 to
0cf11c3
Compare
Co-authored-by: Guillaume de Rouville <guillaume@dagger.io> Signed-off-by: Tibor Vass <teabee89@gmail.com> Signed-off-by: Guillaume de Rouville <guillaume@dagger.io>
So far we were using the terminal session attachable to pass data between cli and engine for the MCP stdio server. However, MCP clients when they execute the cli they don't provide a TTY. The new pipe session attachable allows to send and receive data between the cli and the engine. Co-authored-by: Guillaume de Rouville <guillaume@dagger.io> Signed-off-by: Tibor Vass <teabee89@gmail.com> Signed-off-by: Guillaume de Rouville <guillaume@dagger.io>
Co-authored-by: Guillaume de Rouville <guillaume@dagger.io> Signed-off-by: Tibor Vass <teabee89@gmail.com> Signed-off-by: Guillaume de Rouville <guillaume@dagger.io>
When a tool is called, new tools may be available for the MCP client, so notify it about the new tools. For example, after a call to a function returning a Container, the client should be able to call container-specific functions. Co-authored-by: Guillaume de Rouville <guillaume@dagger.io> Signed-off-by: Tibor Vass <teabee89@gmail.com> Signed-off-by: Guillaume de Rouville <guillaume@dagger.io>
Signed-off-by: Tibor Vass <teabee89@gmail.com> Signed-off-by: Guillaume de Rouville <guillaume@dagger.io>
Signed-off-by: Tibor Vass <teabee89@gmail.com> Signed-off-by: Guillaume de Rouville <guillaume@dagger.io>
Signed-off-by: Tibor Vass <teabee89@gmail.com> Signed-off-by: Guillaume de Rouville <guillaume@dagger.io>
Signed-off-by: Tibor Vass <teabee89@gmail.com> Signed-off-by: Guillaume de Rouville <guillaume@dagger.io>
Co-authored-by: Guillaume de Rouville <guillaume@dagger.io> Signed-off-by: Tibor Vass <teabee89@gmail.com> Signed-off-by: Guillaume de Rouville <guillaume@dagger.io>
Signed-off-by: Tibor Vass <teabee89@gmail.com> Signed-off-by: Guillaume de Rouville <guillaume@dagger.io>
This fixes a bug where MCP clients would see unavailable tools and would attempt to use them and receive a cryptic error. Signed-off-by: Tibor Vass <teabee89@gmail.com> Signed-off-by: Guillaume de Rouville <guillaume@dagger.io>
…erveStdio() The idea is to then have: mcp.ServeStdio() potentially in the API ? Signed-off-by: Guillaume de Rouville <guillaume@dagger.io>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In a good shape ✅
Some of the todos left, but good enough for beta testing. Everything is hidden, under the hidden dagger mcp command ; AND, everything is scoped to the dagger mcp subcommand -- no impact on main branch at all
How to test it (dev mode):
OPENAI_API_KEY=toto dagger_dev --progress plain mcp -m github.com/shykes/helloNotes
- The options
--progress plainor-sare mandatory atm to not have thestdinpolluted. One of the todos is to override it when not set in the CLI - One of the provider key is still mandatory as our
MCPmethod is still part ofLLM
Then you can paste this on stdio:
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"capabilities":{},"clientInfo":{"name":"goose","version":"1.0.12"},"protocolVersion":"1.0.0"}}
{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}
{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"arguments":{"name":"Fred"},"name":"Hello_hello"}}
This introduces a new
dagger mcpcommand that starts an MCP stdio serverUsage
dagger mcpordagger mcp -m ref, where therefis a path to a local module or a remote oneImplementation
In this version, each dagger function corresponds to an MCP tool.
When a function is called, the list of available tools is refreshed. This allows the LLM to handle objects it didn't know previously. Such is the case for a function returning a
dagger.Container.The MCP server lives on the engine side, and the
dagger mcpcommand simply forwards the stdio pipes to it using a new Pipe session attachable.Integrating this command with your IDE / other MCP clients
mcp_config.json:{ "mcpServers": { "dagger": { "command": "/path/to/dev/dagger", "env": { "_EXPERIMENTAL_DAGGER_RUNNER_HOST":"docker-container://dagger-engine.dev", "OPENAI_API_KEY":"toto" }, "args": [ "mcp", "-m", "ref/to/module" ] } } }Current capabilities supported
Analysis of Client support
Todo
OPENAI_API_KEYor equivalent needs to be set (can be justfoo) because MCP is a method on the LLM object even though MCP doesn't make API calls. This requirement will go away as we separate MCP from LLM.-sor--progress plainneeds to be specified so only stderr is used, asdagger mcpcommand uses bothstdinandstdoutfor MCP communication. We could force--progress plain, or decide on a minimalist reporting when using-s.dagger call? Or should we piggyback ondagger shellby instead doingdagger -c "... | mcp"? (Would need to think how that could work on the client side...). Ordagger mcp -c '...'ordagger -mcp -c '...'?*_idfunctions should not be exposed to MCP. Apparently it's still exposed despite logic attempting to prevent it.Co-authored by @grouville