Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/check-licenses.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ jobs:
- name: Check licenses
run: |
go-licenses check ./... \
--ignore github.com/xi2/xz,golang.org/x/sys/unix # https://github.com/xi2/xz/blob/master/LICENSE
--ignore github.com/xi2/xz,golang.org/x/sys/unix,github.com/segmentio/asm # https://github.com/xi2/xz/blob/master/LICENSE
1 change: 1 addition & 0 deletions cmd/porter/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ Try our QuickStart https://porter.sh/quickstart to learn how to use Porter.
cmd.AddCommand(buildParametersCommands(p))
cmd.AddCommand(buildConfigCommands(p))
cmd.AddCommand(buildCompletionCommand(p))
cmd.AddCommand(buildMCPCommand(p))
//use -ldflags "-X main.includeGRPCServer=true" during build to include
grpcServer, _ := strconv.ParseBool(includeGRPCServer)
if grpcServer {
Expand Down
34 changes: 34 additions & 0 deletions cmd/porter/mcp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package main

import (
"get.porter.sh/porter/pkg/mcp"
"get.porter.sh/porter/pkg/porter"
"github.com/spf13/cobra"
)

func buildMCPCommand(p *porter.Porter) *cobra.Command {
opts := mcp.ServerOptions{}
cmd := &cobra.Command{
Use: "mcp",
Short: "Start an MCP server over stdio",
Long: `Start a Model Context Protocol (MCP) server that exposes Porter
operations as tools for LLM agents.

The server communicates over stdin/stdout using the MCP protocol.
Read-only tools are always available. Mutating tools (install, upgrade,
uninstall, invoke) require the --allow-write flag.

Configure your MCP client (e.g. Claude Desktop) with:
{"command": "porter", "args": ["mcp"]}
`,
RunE: func(cmd *cobra.Command, args []string) error {
srv := mcp.NewMCPServer(p, opts)
srv.RegisterTools()
return srv.ServeStdio(cmd.Context())
},
}
f := cmd.Flags()
f.BoolVar(&opts.AllowWrite, "allow-write", false,
"Enable mutating tools: install, upgrade, uninstall, invoke")
return cmd
}
3 changes: 2 additions & 1 deletion docs/content/docs/how-to-guides/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ aliases:
- /how-to-guides/
---

**Guides for working with Mixins and Plugins**
**Guides for working with Mixins, Plugins, and AI Agents**

{{< cards >}}
{{< card link="work-with-mixins/" title="Working with Mixins" >}}
{{< card link="work-with-plugins/" title="Working with Plugins" >}}
{{< card link="work-with-ai-agents/" title="Working with AI Agents" >}}
{{< /cards >}}
147 changes: 147 additions & 0 deletions docs/content/docs/how-to-guides/work-with-ai-agents.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
---
title: Working with AI Agents
description: Connect AI coding assistants and LLM agents to Porter using the Model Context Protocol.
weight: 3
aliases:
- /how-to-guides/work-with-ai-agents/
---

Porter includes a built-in [Model Context Protocol (MCP)][mcp] server that
exposes bundle operations as tools for LLM agents and AI coding assistants such
as Claude Code, Cursor, and VS Code Copilot. This lets an agent install,
inspect, and troubleshoot bundles on your behalf using natural language.

- [Prerequisites](#prerequisites)
- [Configure your MCP client](#configure-your-mcp-client)
- [Claude Code](#claude-code)
- [VS Code (GitHub Copilot)](#vs-code-github-copilot)
- [Cursor](#cursor)
- [Available tools](#available-tools)
- [Enabling write operations](#enabling-write-operations)
- [Security considerations](#security-considerations)

## Prerequisites

- Porter [installed and configured](/install/)
- An MCP-compatible AI client (Claude Code, Cursor, VS Code Copilot, etc.)

## Configure your MCP client

Porter's MCP server communicates over stdin/stdout. All clients need the same
two values:

| Setting | Value |
|---------|-------|
| **command** | `porter` |
| **args** | `["mcp"]` |

### Claude Code

Add the server to your project:

```console
claude mcp add porter -- porter mcp
```

Or add it to your user-level configuration so it is available in every project:

```console
claude mcp add --scope user porter -- porter mcp
```

Verify the server is registered:

```console
claude mcp list
```

### VS Code (GitHub Copilot)

Add to `.vscode/mcp.json` in your workspace:

```json
{
"servers": {
"porter": {
"type": "stdio",
"command": "porter",
"args": ["mcp"]
}
}
}
```

### Cursor

Open **Cursor Settings → MCP** and add:

```json
{
"porter": {
"command": "porter",
"args": ["mcp"]
}
}
```

## Available tools

### Read-only tools (always available)

| Tool | What the agent can do |
|------|-----------------------|
| `explain_bundle` | Show parameters, credentials, outputs, and actions of a published bundle by OCI reference |
| `list_installations` | List Porter installations, optionally filtered by namespace or name |
| `show_installation` | Show the current status and details of a specific installation |
| `list_runs` | List execution history for an installation |
| `get_logs` | Retrieve logs from a run (latest run or a specific run ID) |
| `list_outputs` | List output values from an installation run (sensitive values are masked) |
| `get_output` | Read a specific output value (blocked for sensitive outputs) |
| `list_credentials` | List available credential sets |
| `show_credential` | Show the definition of a credential set |
| `list_parameters` | List available parameter sets |
| `show_parameter` | Show the definition of a parameter set |
| `analyze_failure` | Aggregate failure context: finds the last failed run (or a specific run by ID) and returns its logs and outputs in one call |

### Write tools (require `--allow-write`)

| Tool | What the agent can do |
|------|-----------------------|
| `install_bundle` | Install a bundle from an OCI reference |
| `upgrade_bundle` | Upgrade an existing installation |
| `uninstall_bundle` | Uninstall an installation |
| `invoke_bundle` | Run a custom action on an installation |

## Enabling write operations

Write tools are disabled by default so that an agent browsing installations
cannot accidentally modify them. Pass `--allow-write` to expose the install,
upgrade, uninstall, and invoke tools:

```console
# Claude Code
claude mcp add porter -- porter mcp --allow-write

# VS Code / Cursor — add "--allow-write" to the args array
"args": ["mcp", "--allow-write"]
```

When `--allow-write` is not set, the write tools are not registered at all and
will not appear in the agent's tool list.

## Security considerations

- **Read-only by default.** Without `--allow-write`, no bundle lifecycle
operations are exposed.
- **Sensitive outputs are masked.** Values marked sensitive in the bundle are
returned as `***` in `list_outputs` and are blocked entirely in `get_output`.
- **Credentials are not exposed.** The server can show the structure of a
credential set (which sources are configured) but never returns the resolved
secret values.
- **Local access only.** The MCP server uses stdio transport; there is no
network listener and no authentication is required or possible.
- **Porter's own access controls apply.** The server runs as the current OS
user with the existing Porter configuration. It can only access namespaces
and plugins that the user can access directly.

[mcp]: https://modelcontextprotocol.io
50 changes: 50 additions & 0 deletions docs/content/docs/references/cli/mcp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
title: "porter mcp"
slug: porter_mcp
url: /cli/porter_mcp/
---
## porter mcp

Start an MCP server over stdio

### Synopsis

Start a Model Context Protocol (MCP) server that exposes Porter
operations as tools for LLM agents.

The server communicates over stdin/stdout using the MCP protocol.
Read-only tools are always available. Mutating tools (install, upgrade,
uninstall, invoke) require the --allow-write flag.

Configure your MCP client (e.g. Claude Desktop) with:
{"command": "porter", "args": ["mcp"]}


```
porter mcp [flags]
```

### Options

```
--allow-write Enable mutating tools: install, upgrade, uninstall, invoke
-h, --help help for mcp
```

### Options inherited from parent commands

```
--context string Name of the configuration context to use. When unset, Porter uses the current-context from the config file, falling back to the context named "default".
--experimental strings Comma separated list of experimental features to enable. See https://porter.sh/configuration/#experimental-feature-flags for available feature flags.
--verbosity string Threshold for printing messages to the console. Available values are: debug, info, warning, error. (default "info")
```

### SEE ALSO

* [porter](/cli/porter/) - With Porter you can package your application artifact, client tools, configuration and deployment logic together as a versioned bundle that you can distribute, and then install with a single command.

Most commands require a Docker daemon, either local or remote.

Try our QuickStart https://porter.sh/quickstart to learn how to use Porter.


1 change: 1 addition & 0 deletions docs/content/docs/references/cli/porter.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ porter [flags]
* [porter lint](/cli/porter_lint/) - Lint a bundle
* [porter list](/cli/porter_list/) - List installed bundles
* [porter logs](/cli/porter_logs/) - Show the logs from an installation
* [porter mcp](/cli/porter_mcp/) - Start an MCP server over stdio
* [porter mixins](/cli/porter_mixins/) - Mixin commands. Mixins assist with authoring bundles.
* [porter parameters](/cli/porter_parameters/) - Parameter set commands
* [porter plugins](/cli/porter_plugins/) - Plugin commands. Plugins enable Porter to work on different cloud providers and systems.
Expand Down
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ require (
github.com/moby/moby/api v1.54.0
github.com/moby/moby/client v0.3.0
github.com/moby/term v0.5.2
github.com/modelcontextprotocol/go-sdk v1.4.1
github.com/olekukonko/tablewriter v1.1.4
github.com/opencontainers/go-digest v1.0.0
github.com/osteele/liquid v1.8.1
Expand Down Expand Up @@ -173,6 +174,7 @@ require (
github.com/golang/snappy v1.0.0 // indirect
github.com/google/certificate-transparency-go v1.3.3 // indirect
github.com/google/gnostic-models v0.7.1 // indirect
github.com/google/jsonschema-go v0.4.2 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect
Expand Down Expand Up @@ -242,6 +244,7 @@ require (
github.com/sagikazarmark/locafero v0.12.0 // indirect
github.com/secure-systems-lab/go-securesystemslib v0.10.0 // indirect
github.com/segmentio/asm v1.2.1 // indirect
github.com/segmentio/encoding v0.5.4 // indirect
github.com/shibumi/go-pathspec v1.3.0 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/sigstore/protobuf-specs v0.5.0 // indirect
Expand Down Expand Up @@ -274,6 +277,7 @@ require (
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/yashtewari/glob-intersection v0.2.0 // indirect
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
github.com/zclconf/go-cty v1.18.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,8 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX
github.com/google/go-containerregistry v0.21.3 h1:Xr+yt3VvwOOn/5nJzd7UoOhwPGiPkYW0zWDLLUXqAi4=
github.com/google/go-containerregistry v0.21.3/go.mod h1:D5ZrJF1e6dMzvInpBPuMCX0FxURz7GLq2rV3Us9aPkc=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/jsonschema-go v0.4.2 h1:tmrUohrwoLZZS/P3x7ex0WAVknEkBZM46iALbcqoRA8=
github.com/google/jsonschema-go v0.4.2/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
Expand Down Expand Up @@ -594,6 +596,8 @@ github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
github.com/modelcontextprotocol/go-sdk v1.4.1 h1:M4x9GyIPj+HoIlHNGpK2hq5o3BFhC+78PkEaldQRphc=
github.com/modelcontextprotocol/go-sdk v1.4.1/go.mod h1:Bo/mS87hPQqHSRkMv4dQq1XCu6zv4INdXnFZabkNU6s=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
Expand Down Expand Up @@ -714,6 +718,8 @@ github.com/secure-systems-lab/go-securesystemslib v0.10.0 h1:l+H5ErcW0PAehBNrBxo
github.com/secure-systems-lab/go-securesystemslib v0.10.0/go.mod h1:MRKONWmRoFzPNQ9USRF9i1mc7MvAVvF1LlW8X5VWDvk=
github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0=
github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
github.com/segmentio/encoding v0.5.4 h1:OW1VRern8Nw6ITAtwSZ7Idrl3MXCFwXHPgqESYfvNt0=
github.com/segmentio/encoding v0.5.4/go.mod h1:HS1ZKa3kSN32ZHVZ7ZLPLXWvOVIiZtyJnO1gPH1sKt0=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw=
github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
Expand Down Expand Up @@ -855,6 +861,8 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yashtewari/glob-intersection v0.2.0 h1:8iuHdN88yYuCzCdjt0gDe+6bAhUwBeEWqThExu54RFg=
github.com/yashtewari/glob-intersection v0.2.0/go.mod h1:LK7pIC3piUjovexikBbJ26Yml7g8xa5bsjfx2v1fwok=
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
Expand Down
Loading
Loading