MCP
Dagger can be used as a programming environment for AI agents. Dagger provides an LLM
core type that enables native integration of Large Language Models (LLM) in your workflows.
Model Context Protocol (MCP) support in Dagger can be broken into three categories:
- MCP within Dagger
- Exposing MCP outside of Dagger
- Connecting to external MCP from Dagger
MCP within Dagger
A key feature of Dagger's LLM integration is out-of-the-box support for MCP using Dagger Functions: an LLM can automatically discover and use any available Dagger Functions in your Module.
LLM Bindings
Here's an example of Dagger's LLM bindings in action:
- Dagger Shell
- System shell
base=$(container | from alpine)
env=$(env | with-container-input 'base' $base 'a base container' | with-container-output 'python-dev' 'a container with python dev tools')
llm | with-env $env | with-prompt "You have an alpine container. Install tools to develop with Python." | env | output python-dev | as-container | terminal
dagger <<EOF
base=\$(container | from alpine)
env=\$(env |
with-container-input 'base' \$base 'a base container' |
with-container-output 'python-dev' 'a container with python dev tools')
llm |
with-env \$env |
with-prompt "You have an alpine container. Install tools to develop with Python." |
env |
output python-dev |
as-container |
terminal
EOF
Agent loop
Consider the following Dagger Function:
- Go
- Python
- TypeScript
package main
import (
"dagger/coding-agent/internal/dagger"
)
type CodingAgent struct{}
// Write a Go program
func (m *CodingAgent) GoProgram(
// The programming assignment, e.g. "write me a curl clone"
assignment string,
) *dagger.Container {
environment := dag.Env().
WithStringInput("assignment", assignment, "the assignment to complete").
WithContainerInput("builder",
dag.Container().From("golang").WithWorkdir("/app"),
"a container to use for building Go code").
WithContainerOutput("completed", "the completed assignment in the Golang container")
work := dag.LLM().
WithEnv(environment).
WithPrompt(`
You are an expert Go programmer with an assignment to create a Go program
Create files in the default directory in $builder
Always build the code to make sure it is valid
Do not stop until your assignment is completed and the code builds
Your assignment is: $assignment
`)
return work.
Env().
Output("completed").
AsContainer()
}
import dagger
from dagger import dag, function, object_type
@object_type
class CodingAgent:
@function
def go_program(
self,
assignment: str,
) -> dagger.Container:
"""Write a Go program"""
environment = (
dag.env()
.with_string_input("assignment", assignment, "the assignment to complete")
.with_container_input(
"builder",
dag.container().from_("golang").with_workdir("/app"),
"a container to use for building Go code",
)
.with_container_output(
"completed", "the completed assignment in the Golang container"
)
)
work = (
dag.llm()
.with_env(environment)
.with_prompt(
"""
You are an expert Go programmer
with an assignment to create a Go program
Create files in the default directory in $builder
Always build the code to make sure it is valid
Do not stop until your assignment is completed and the code builds
Your assignment is: $assignment"""
)
)
return work.env().output("completed").as_container()
import { dag, object, func, Container } from "@dagger.io/dagger"
@object()
export class CodingAgent {
/**
* Write a Go program
*/
@func()
goProgram(
/**
* The programming assignment, e.g. "write me a curl clone"
*/
assignment: string,
): Container {
const environment = dag
.env()
.withStringInput("assignment", assignment, "the assignment to complete")
.withContainerInput(
"builder",
dag.container().from("golang").withWorkdir("/app"),
"a container to use for building Go code",
)
.withContainerOutput(
"completed",
"the completed assignment in the Golang container",
)
const work = dag
.llm()
.withEnv(environment)
.withPrompt(
`You are an expert Go programmer with an assignment to create a Go program
Create files in the default directory in $builder
Always build the code to make sure it is valid
Do not stop until your assignment is completed and the code builds
Your assignment is: $assignment`,
)
return work.env().output("completed").asContainer()
}
}
This Dagger Function creates a new LLM, gives it an environment (a container with various tools) with an assignment, and prompts it to complete the assignment. The LLM then runs in a loop, calling tools and iterating on its work, until it completes the assignment. This loop all happens inside of the LLM object, so the value of result
is the environment with the completed assignment.
Exposing MCP outside of Dagger
Dagger has built-in MCP support that allows you to easily expose Dagger modules as an MCP server. This allows you to configure a client (such as Claude Desktop, Cursor, Goose CLI/Desktop) to consume modules from the Daggerverse or any git repo as native MCP servers.
Today only modules with no required constructor arguments are supported when exposing an MCP server outside of Dagger.
Connecting to External MCP Server from Dagger
Support for connecting to external MCP servers from Dagger is coming soon.