diff --git a/.github/workflows/publish-mcp-registry.yaml b/.github/workflows/publish-mcp-registry.yaml new file mode 100644 index 0000000000..d1b7111d01 --- /dev/null +++ b/.github/workflows/publish-mcp-registry.yaml @@ -0,0 +1,80 @@ +name: Publish to MCP Registry + +on: + release: + types: [published] + workflow_dispatch: + inputs: + version: + description: "Version to publish (semver, e.g. 2.20.0). Used only for manual runs." + required: false + type: string + publish: + description: "Actually publish to the live registry. Leave false to validate only." + required: false + default: false + type: boolean + +jobs: + publish-mcp: + runs-on: ubuntu-latest + permissions: + id-token: write # Required for GitHub OIDC + contents: read + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Install mcp-publisher + run: | + curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher + + - name: Determine version + id: version + env: + EVENT_NAME: ${{ github.event_name }} + INPUT_VERSION: ${{ inputs.version }} + run: | + set -euo pipefail + if [ "${EVENT_NAME}" = "release" ]; then + # Tag refs look like refs/tags/v2.20.0 + VERSION="${GITHUB_REF#refs/tags/v}" + else + VERSION="${INPUT_VERSION}" + fi + + if [ -z "${VERSION}" ]; then + echo "::error::No version provided. Pass the 'version' input for manual runs." + exit 1 + fi + + # Reject anything that isn't clean semver so we never publish refs/heads/... etc. + if ! echo "${VERSION}" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$'; then + echo "::error::Refusing to publish invalid version '${VERSION}'." + exit 1 + fi + + echo "version=${VERSION}" >> "${GITHUB_OUTPUT}" + + - name: Set version in server.json + env: + VERSION: ${{ steps.version.outputs.version }} + run: | + set -euo pipefail + jq --arg v "${VERSION}" '.version = $v' server.json > server.tmp + mv server.tmp server.json + cat server.json + + - name: Validate server.json (no publish) + run: ./mcp-publisher validate + + - name: Authenticate to MCP Registry + if: github.event_name == 'release' || inputs.publish + run: ./mcp-publisher login github-oidc + + - name: Publish server to MCP Registry + if: github.event_name == 'release' || inputs.publish + run: ./mcp-publisher publish diff --git a/docs/ai-coder/mcp-server.md b/docs/ai-coder/mcp-server.md index 3a3ea42b98..bd86b17761 100644 --- a/docs/ai-coder/mcp-server.md +++ b/docs/ai-coder/mcp-server.md @@ -1,58 +1,217 @@ # MCP Server -Power users can configure [claude.ai](https://claude.ai), Claude Desktop, Cursor, or other external agents to interact with Coder in order to: +Coder includes a built-in [Model Context Protocol](https://modelcontextprotocol.io/) +(MCP) server that provides AI assistants with tools and context about your Coder +deployment. This enables AI-powered workflows for managing workspaces, +templates, and development environments. -- List workspaces -- Create/start/stop workspaces -- Run commands on workspaces -- Check in on agent activity +Coder supports two MCP server modes: -> [!NOTE] -> See our [toolsdk](https://pkg.go.dev/github.com/coder/coder/v2/codersdk/toolsdk#pkg-variables) documentation for a full list of tools included in the MCP server +- **[Local MCP Server](#local-mcp-server)**: Runs via the Coder CLI using stdio + transport. Ideal for local AI tools and IDE integrations. +- **[Remote MCP Server](#remote-mcp-server)**: HTTP-based server exposed by your + Coder deployment. Supports OAuth2 authentication and is published to the MCP + Registry. -In this model, any custom agent could interact with a remote Coder workspace, or Coder can be used in a remote pipeline or a larger workflow. +## Local MCP Server -## Local MCP server +The local MCP server runs via the Coder CLI and uses stdio transport to +communicate with AI tools. -The Coder CLI has options to automatically configure MCP servers for you. On your local machine, run the following command: +### Setup -```sh -# First log in to Coder. -coder login - -# Configure your client with the Coder MCP -coder exp mcp configure claude-desktop # Configure Claude Desktop to interact with Coder -coder exp mcp configure cursor # Configure Cursor to interact with Coder -``` - -For other agents, run the MCP server with this command: +Run the MCP server using the Coder CLI: ```sh coder exp mcp server ``` -> [!NOTE] -> The MCP server is authenticated with the same identity as your Coder CLI and can perform any action on the user's behalf. Fine-grained permissions are in development. [Contact us](https://coder.com/contact) if this use case is important to you. +### Client Configuration -## Remote MCP server +Configure your MCP client to spawn the Coder CLI: -Coder can expose an MCP server via HTTP. This is useful for connecting web-based agents, like https://claude.ai/, to Coder. This is an experimental feature and is subject to change. +```json +{ + "mcpServers": { + "coder": { + "command": "coder", + "args": ["exp", "mcp", "server"] + } + } +} +``` -To enable this feature, activate the `oauth2` and `mcp-server-http` experiments using an environment variable or a CLI flag: +The CLI automatically uses your existing Coder authentication (from `coder login`). + +### Claude Desktop Example + +Add to your Claude Desktop configuration file: + +
+ +#### macOS + +Edit `~/Library/Application Support/Claude/claude_desktop_config.json`: + +```json +{ + "mcpServers": { + "coder": { + "command": "coder", + "args": ["exp", "mcp", "server"] + } + } +} +``` + +#### Windows + +Edit `%APPDATA%\Claude\claude_desktop_config.json`: + +```json +{ + "mcpServers": { + "coder": { + "command": "coder.exe", + "args": ["exp", "mcp", "server"] + } + } +} +``` + +
+ +## Remote MCP Server + +The remote MCP server is an HTTP endpoint exposed by your Coder deployment at +`/api/experimental/mcp/http`. This enables MCP clients to connect to Coder +without running the CLI locally. + +### Prerequisites + +The remote MCP HTTP endpoint requires both the `oauth2` and `mcp-server-http` +experiments enabled on your Coder deployment: ```sh -CODER_EXPERIMENTS="oauth2,mcp-server-http" coder server -# or coder server --experiments=oauth2,mcp-server-http ``` -The Coder server will expose the MCP server at: +Or set the environment variable: -```txt -https://coder.example.com/api/experimental/mcp/http +```sh +CODER_EXPERIMENTS=oauth2,mcp-server-http ``` -> [!NOTE] -> At this time, the remote MCP server is not compatible with web-based ChatGPT. +### MCP Registry -Users can authenticate applications to use the remote MCP server with [OAuth2](../admin/integrations/oauth2-provider.md). An authenticated application can perform any action on the user's behalf. Fine-grained permissions are in development. +Coder is published to the official [MCP Registry](https://github.com/modelcontextprotocol/registry) +as `io.github.coder/coder`, enabling easy installation in supported MCP clients. + +#### VS Code / GitHub Copilot + +1. Open VS Code Command Palette and run **MCP: Add Server...** +1. Select **From MCP Registry** +1. Search for "Coder" and select it +1. Enter your Coder deployment URL when prompted (e.g., `https://coder.example.com`) +1. VS Code will automatically handle OAuth2 authentication + +#### Claude Desktop (Remote) + +Add to your Claude Desktop configuration file (`claude_desktop_config.json`): + +```json +{ + "mcpServers": { + "coder": { + "url": "https://coder.example.com/api/experimental/mcp/http" + } + } +} +``` + +Claude Desktop will automatically discover OAuth2 endpoints and prompt you to +authenticate through your browser. + +### Manual Configuration + +For MCP clients that don't support the registry or OAuth2 discovery, configure +the server manually with a session token: + +```json +{ + "mcpServers": { + "coder": { + "url": "https://coder.example.com/api/experimental/mcp/http", + "headers": { + "Coder-Session-Token": "" + } + } + } +} +``` + +To create a session token: + +1. Navigate to your Coder deployment +1. Go to **Settings > Tokens** +1. Create a new token +1. Add the token to your MCP client configuration + +## Authentication + +The MCP server supports two authentication methods: + +### OAuth2 (Recommended for Interactive Clients) + +MCP clients that support [RFC 9728](https://datatracker.ietf.org/doc/html/rfc9728) +(Protected Resource Metadata) can authenticate automatically using OAuth2. The +server advertises its OAuth2 capabilities via the `WWW-Authenticate` header and +`/.well-known/oauth-protected-resource` endpoint. + +This enables a seamless "click-to-connect" experience where users authenticate +through their browser without manually managing tokens. + +> [!NOTE] +> OAuth2 requires the `oauth2` experiment to be enabled on your Coder deployment. + +### Session Token (For Programmatic Access) + +For clients that don't support OAuth2 discovery, or for programmatic access, use +a session token as shown in the [Manual Configuration](#manual-configuration) +section. + +## Available Tools + +The MCP server exposes tools across several areas: + +- **Workspace management**: list, inspect, create, and build workspaces +- **Template operations**: list, inspect, create, and manage templates and versions +- **File operations**: read, write, and edit files in a workspace +- **Workspace interaction**: run commands, forward ports, list apps, and read logs +- **Task management**: create, list, inspect, and control tasks +- **User and system**: authenticated user details, tar uploads, and task reporting + +The full, authoritative set of tools, including their names, descriptions, and +arguments, is defined in Coder's +[`toolsdk` package](../../codersdk/toolsdk/toolsdk.go). Refer to it for the +current list, since the available tools can change between releases. + +## Troubleshooting + +### "Unauthorized" errors + +- Verify your session token is valid and not expired +- Check that the MCP server experiment is enabled on your deployment +- Ensure your user has appropriate permissions for the requested operations + +### Connection timeouts + +- Verify your Coder deployment URL is correct and accessible +- Check network connectivity between your MCP client and the Coder server +- Review Coder server logs for any errors + +### OAuth2 authentication not working + +- Ensure your Coder deployment has the `oauth2` experiment enabled +- Verify your MCP client supports RFC 9728 Protected Resource Metadata +- Check that your browser can reach the Coder authorization endpoint diff --git a/server.json b/server.json new file mode 100644 index 0000000000..a143951306 --- /dev/null +++ b/server.json @@ -0,0 +1,47 @@ +{ + "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json", + "name": "io.github.coder/coder", + "title": "Coder", + "description": "Manage Coder workspaces, templates, and cloud development environments", + "repository": { + "url": "https://github.com/coder/coder", + "source": "github" + }, + "version": "0.0.0-dev", + "websiteUrl": "https://coder.com/docs", + "icons": [ + { + "src": "https://raw.githubusercontent.com/coder/coder/main/docs/images/logo-black.png", + "mimeType": "image/png" + } + ], + "remotes": [ + { + "type": "streamable-http", + "url": "{coder_url}/api/experimental/mcp/http", + "variables": { + "coder_url": { + "description": "URL of your Coder deployment (e.g., https://coder.example.com)", + "isRequired": true, + "format": "string", + "placeholder": "https://coder.example.com" + } + } + } + ], + "_meta": { + "io.modelcontextprotocol.registry/publisher-provided": { + "documentation": "https://coder.com/docs/ai-coder/mcp-server", + "keywords": [ + "workspaces", + "cloud-development", + "templates", + "devcontainers", + "terraform", + "self-hosted" + ], + "license": "AGPL-3.0", + "publisher": "Coder" + } + } +}