mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
feat: implement MCP HTTP server endpoint with authentication (#18670)
# Add MCP HTTP server with streamable transport support - Add MCP HTTP server with streamable transport support - Integrate with existing toolsdk for Coder workspace operations - Add comprehensive E2E tests with OAuth2 bearer token support - Register MCP endpoint at /api/experimental/mcp/http with authentication - Support RFC 6750 Bearer token authentication for MCP clients Change-Id: Ib9024569ae452729908797c42155006aa04330af Signed-off-by: Thomas Kosiewski <tk@coder.com>
This commit is contained in:
Generated
+67
-1
@@ -11711,7 +11711,73 @@ const docTemplate = `{
|
||||
}
|
||||
},
|
||||
"codersdk.CreateTestAuditLogRequest": {
|
||||
"type": "object"
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"enum": [
|
||||
"create",
|
||||
"write",
|
||||
"delete",
|
||||
"start",
|
||||
"stop"
|
||||
],
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/codersdk.AuditAction"
|
||||
}
|
||||
]
|
||||
},
|
||||
"additional_fields": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"build_reason": {
|
||||
"enum": [
|
||||
"autostart",
|
||||
"autostop",
|
||||
"initiator"
|
||||
],
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/codersdk.BuildReason"
|
||||
}
|
||||
]
|
||||
},
|
||||
"organization_id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"request_id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"resource_id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"resource_type": {
|
||||
"enum": [
|
||||
"template",
|
||||
"template_version",
|
||||
"user",
|
||||
"workspace",
|
||||
"workspace_build",
|
||||
"git_ssh_key",
|
||||
"auditable_group"
|
||||
],
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/codersdk.ResourceType"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.CreateTokenRequest": {
|
||||
"type": "object",
|
||||
|
||||
Generated
+57
-1
@@ -10427,7 +10427,63 @@
|
||||
}
|
||||
},
|
||||
"codersdk.CreateTestAuditLogRequest": {
|
||||
"type": "object"
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"enum": ["create", "write", "delete", "start", "stop"],
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/codersdk.AuditAction"
|
||||
}
|
||||
]
|
||||
},
|
||||
"additional_fields": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"build_reason": {
|
||||
"enum": ["autostart", "autostop", "initiator"],
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/codersdk.BuildReason"
|
||||
}
|
||||
]
|
||||
},
|
||||
"organization_id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"request_id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"resource_id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"resource_type": {
|
||||
"enum": [
|
||||
"template",
|
||||
"template_version",
|
||||
"user",
|
||||
"workspace",
|
||||
"workspace_build",
|
||||
"git_ssh_key",
|
||||
"auditable_group"
|
||||
],
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/codersdk.ResourceType"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.CreateTokenRequest": {
|
||||
"type": "object",
|
||||
|
||||
@@ -972,6 +972,10 @@ func New(options *Options) *API {
|
||||
r.Route("/aitasks", func(r chi.Router) {
|
||||
r.Get("/prompts", api.aiTasksPrompts)
|
||||
})
|
||||
r.Route("/mcp", func(r chi.Router) {
|
||||
// MCP HTTP transport endpoint with mandatory authentication
|
||||
r.Mount("/http", api.mcpHTTPHandler())
|
||||
})
|
||||
})
|
||||
|
||||
r.Route("/api/v2", func(r chi.Router) {
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
package mcp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/mark3labs/mcp-go/mcp"
|
||||
"github.com/mark3labs/mcp-go/server"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"cdr.dev/slog"
|
||||
|
||||
"github.com/coder/coder/v2/buildinfo"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
"github.com/coder/coder/v2/codersdk/toolsdk"
|
||||
)
|
||||
|
||||
const (
|
||||
// MCPServerName is the name used for the MCP server.
|
||||
MCPServerName = "Coder"
|
||||
// MCPServerInstructions is the instructions text for the MCP server.
|
||||
MCPServerInstructions = "Coder MCP Server providing workspace and template management tools"
|
||||
)
|
||||
|
||||
// Server represents an MCP HTTP server instance
|
||||
type Server struct {
|
||||
Logger slog.Logger
|
||||
|
||||
// mcpServer is the underlying MCP server
|
||||
mcpServer *server.MCPServer
|
||||
|
||||
// streamableServer handles HTTP transport
|
||||
streamableServer *server.StreamableHTTPServer
|
||||
}
|
||||
|
||||
// NewServer creates a new MCP HTTP server
|
||||
func NewServer(logger slog.Logger) (*Server, error) {
|
||||
// Create the core MCP server
|
||||
mcpSrv := server.NewMCPServer(
|
||||
MCPServerName,
|
||||
buildinfo.Version(),
|
||||
server.WithInstructions(MCPServerInstructions),
|
||||
)
|
||||
|
||||
// Create logger adapter for mcp-go
|
||||
mcpLogger := &mcpLoggerAdapter{logger: logger}
|
||||
|
||||
// Create streamable HTTP server with configuration
|
||||
streamableServer := server.NewStreamableHTTPServer(mcpSrv,
|
||||
server.WithHeartbeatInterval(30*time.Second),
|
||||
server.WithLogger(mcpLogger),
|
||||
)
|
||||
|
||||
return &Server{
|
||||
Logger: logger,
|
||||
mcpServer: mcpSrv,
|
||||
streamableServer: streamableServer,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ServeHTTP implements http.Handler interface
|
||||
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
s.streamableServer.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// RegisterTools registers all available MCP tools with the server
|
||||
func (s *Server) RegisterTools(client *codersdk.Client) error {
|
||||
if client == nil {
|
||||
return xerrors.New("client cannot be nil: MCP HTTP server requires authenticated client")
|
||||
}
|
||||
|
||||
// Create tool dependencies
|
||||
toolDeps, err := toolsdk.NewDeps(client)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to initialize tool dependencies: %w", err)
|
||||
}
|
||||
|
||||
// Register all available tools
|
||||
for _, tool := range toolsdk.All {
|
||||
s.mcpServer.AddTools(mcpFromSDK(tool, toolDeps))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// mcpFromSDK adapts a toolsdk.Tool to go-mcp's server.ServerTool
|
||||
func mcpFromSDK(sdkTool toolsdk.GenericTool, tb toolsdk.Deps) server.ServerTool {
|
||||
if sdkTool.Schema.Properties == nil {
|
||||
panic("developer error: schema properties cannot be nil")
|
||||
}
|
||||
|
||||
return server.ServerTool{
|
||||
Tool: mcp.Tool{
|
||||
Name: sdkTool.Name,
|
||||
Description: sdkTool.Description,
|
||||
InputSchema: mcp.ToolInputSchema{
|
||||
Type: "object",
|
||||
Properties: sdkTool.Schema.Properties,
|
||||
Required: sdkTool.Schema.Required,
|
||||
},
|
||||
},
|
||||
Handler: func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
var buf bytes.Buffer
|
||||
if err := json.NewEncoder(&buf).Encode(request.Params.Arguments); err != nil {
|
||||
return nil, xerrors.Errorf("failed to encode request arguments: %w", err)
|
||||
}
|
||||
result, err := sdkTool.Handler(ctx, tb, buf.Bytes())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mcp.CallToolResult{
|
||||
Content: []mcp.Content{
|
||||
mcp.NewTextContent(string(result)),
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// mcpLoggerAdapter adapts slog.Logger to the mcp-go util.Logger interface
|
||||
type mcpLoggerAdapter struct {
|
||||
logger slog.Logger
|
||||
}
|
||||
|
||||
func (l *mcpLoggerAdapter) Infof(format string, v ...any) {
|
||||
l.logger.Info(context.Background(), fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
func (l *mcpLoggerAdapter) Errorf(format string, v ...any) {
|
||||
l.logger.Error(context.Background(), fmt.Sprintf(format, v...))
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,133 @@
|
||||
package mcp_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/mark3labs/mcp-go/mcp"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
mcpserver "github.com/coder/coder/v2/coderd/mcp"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
"github.com/coder/coder/v2/codersdk/toolsdk"
|
||||
"github.com/coder/coder/v2/testutil"
|
||||
)
|
||||
|
||||
func TestMCPServer_Creation(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
logger := testutil.Logger(t)
|
||||
|
||||
server, err := mcpserver.NewServer(logger)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, server)
|
||||
}
|
||||
|
||||
func TestMCPServer_Handler(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
logger := testutil.Logger(t)
|
||||
|
||||
server, err := mcpserver.NewServer(logger)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test that server implements http.Handler interface
|
||||
var handler http.Handler = server
|
||||
require.NotNil(t, handler)
|
||||
}
|
||||
|
||||
func TestMCPHTTP_InitializeRequest(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
logger := testutil.Logger(t)
|
||||
|
||||
server, err := mcpserver.NewServer(logger)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Use server directly as http.Handler
|
||||
handler := server
|
||||
|
||||
// Create initialize request
|
||||
initRequest := map[string]any{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"method": "initialize",
|
||||
"params": map[string]any{
|
||||
"protocolVersion": mcp.LATEST_PROTOCOL_VERSION,
|
||||
"capabilities": map[string]any{},
|
||||
"clientInfo": map[string]any{
|
||||
"name": "test-client",
|
||||
"version": "1.0.0",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
body, err := json.Marshal(initRequest)
|
||||
require.NoError(t, err)
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "/", bytes.NewReader(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Accept", "application/json,text/event-stream")
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
handler.ServeHTTP(recorder, req)
|
||||
|
||||
if recorder.Code != http.StatusOK {
|
||||
t.Logf("Response body: %s", recorder.Body.String())
|
||||
}
|
||||
assert.Equal(t, http.StatusOK, recorder.Code)
|
||||
|
||||
// Check that a session ID was returned
|
||||
sessionID := recorder.Header().Get("Mcp-Session-Id")
|
||||
assert.NotEmpty(t, sessionID)
|
||||
|
||||
// Parse response
|
||||
var response map[string]any
|
||||
err = json.Unmarshal(recorder.Body.Bytes(), &response)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "2.0", response["jsonrpc"])
|
||||
assert.Equal(t, float64(1), response["id"])
|
||||
|
||||
result, ok := response["result"].(map[string]any)
|
||||
require.True(t, ok)
|
||||
|
||||
assert.Equal(t, mcp.LATEST_PROTOCOL_VERSION, result["protocolVersion"])
|
||||
assert.Contains(t, result, "capabilities")
|
||||
assert.Contains(t, result, "serverInfo")
|
||||
}
|
||||
|
||||
func TestMCPHTTP_ToolRegistration(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
logger := testutil.Logger(t)
|
||||
|
||||
server, err := mcpserver.NewServer(logger)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test registering tools with nil client should return error
|
||||
err = server.RegisterTools(nil)
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "client cannot be nil", "Should reject nil client with appropriate error message")
|
||||
|
||||
// Test registering tools with valid client should succeed
|
||||
client := &codersdk.Client{}
|
||||
err = server.RegisterTools(client)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify that all expected tools are available in the toolsdk
|
||||
expectedToolCount := len(toolsdk.All)
|
||||
require.Greater(t, expectedToolCount, 0, "Should have some tools available")
|
||||
|
||||
// Verify specific tools are present by checking tool names
|
||||
toolNames := make([]string, len(toolsdk.All))
|
||||
for i, tool := range toolsdk.All {
|
||||
toolNames[i] = tool.Name
|
||||
}
|
||||
require.Contains(t, toolNames, toolsdk.ToolNameReportTask, "Should include ReportTask (UserClientOptional)")
|
||||
require.Contains(t, toolNames, toolsdk.ToolNameGetAuthenticatedUser, "Should include GetAuthenticatedUser (requires auth)")
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package coderd
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"cdr.dev/slog"
|
||||
|
||||
"github.com/coder/coder/v2/coderd/httpapi"
|
||||
"github.com/coder/coder/v2/coderd/httpmw"
|
||||
"github.com/coder/coder/v2/coderd/mcp"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
)
|
||||
|
||||
// mcpHTTPHandler creates the MCP HTTP transport handler
|
||||
func (api *API) mcpHTTPHandler() http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Create MCP server instance for each request
|
||||
mcpServer, err := mcp.NewServer(api.Logger.Named("mcp"))
|
||||
if err != nil {
|
||||
api.Logger.Error(r.Context(), "failed to create MCP server", slog.Error(err))
|
||||
httpapi.Write(r.Context(), w, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "MCP server initialization failed",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
authenticatedClient := codersdk.New(api.AccessURL)
|
||||
// Extract the original session token from the request
|
||||
authenticatedClient.SetSessionToken(httpmw.APITokenFromRequest(r))
|
||||
|
||||
// Register tools with authenticated client
|
||||
if err := mcpServer.RegisterTools(authenticatedClient); err != nil {
|
||||
api.Logger.Warn(r.Context(), "failed to register MCP tools", slog.Error(err))
|
||||
}
|
||||
|
||||
// Handle the MCP request
|
||||
mcpServer.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
+7
-2
@@ -536,12 +536,13 @@ func (api *API) postOAuth2ClientRegistration(rw http.ResponseWriter, r *http.Req
|
||||
|
||||
// Store in database - use system context since this is a public endpoint
|
||||
now := dbtime.Now()
|
||||
clientName := req.GenerateClientName()
|
||||
//nolint:gocritic // Dynamic client registration is a public endpoint, system access required
|
||||
app, err := api.Database.InsertOAuth2ProviderApp(dbauthz.AsSystemRestricted(ctx), database.InsertOAuth2ProviderAppParams{
|
||||
ID: clientID,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
Name: req.GenerateClientName(),
|
||||
Name: clientName,
|
||||
Icon: req.LogoURI,
|
||||
CallbackURL: req.RedirectURIs[0], // Primary redirect URI
|
||||
RedirectUris: req.RedirectURIs,
|
||||
@@ -566,7 +567,11 @@ func (api *API) postOAuth2ClientRegistration(rw http.ResponseWriter, r *http.Req
|
||||
RegistrationClientUri: sql.NullString{String: fmt.Sprintf("%s/oauth2/clients/%s", api.AccessURL.String(), clientID), Valid: true},
|
||||
})
|
||||
if err != nil {
|
||||
api.Logger.Error(ctx, "failed to store oauth2 client registration", slog.Error(err))
|
||||
api.Logger.Error(ctx, "failed to store oauth2 client registration",
|
||||
slog.Error(err),
|
||||
slog.F("client_name", clientName),
|
||||
slog.F("client_id", clientID.String()),
|
||||
slog.F("redirect_uris", req.RedirectURIs))
|
||||
writeOAuth2RegistrationError(ctx, rw, http.StatusInternalServerError,
|
||||
"server_error", "Failed to store client registration")
|
||||
return
|
||||
|
||||
+36
-16
@@ -15,6 +15,26 @@ import (
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
)
|
||||
|
||||
// Tool name constants to avoid hardcoded strings
|
||||
const (
|
||||
ToolNameReportTask = "coder_report_task"
|
||||
ToolNameGetWorkspace = "coder_get_workspace"
|
||||
ToolNameCreateWorkspace = "coder_create_workspace"
|
||||
ToolNameListWorkspaces = "coder_list_workspaces"
|
||||
ToolNameListTemplates = "coder_list_templates"
|
||||
ToolNameListTemplateVersionParams = "coder_template_version_parameters"
|
||||
ToolNameGetAuthenticatedUser = "coder_get_authenticated_user"
|
||||
ToolNameCreateWorkspaceBuild = "coder_create_workspace_build"
|
||||
ToolNameCreateTemplateVersion = "coder_create_template_version"
|
||||
ToolNameGetWorkspaceAgentLogs = "coder_get_workspace_agent_logs"
|
||||
ToolNameGetWorkspaceBuildLogs = "coder_get_workspace_build_logs"
|
||||
ToolNameGetTemplateVersionLogs = "coder_get_template_version_logs"
|
||||
ToolNameUpdateTemplateActiveVersion = "coder_update_template_active_version"
|
||||
ToolNameUploadTarFile = "coder_upload_tar_file"
|
||||
ToolNameCreateTemplate = "coder_create_template"
|
||||
ToolNameDeleteTemplate = "coder_delete_template"
|
||||
)
|
||||
|
||||
func NewDeps(client *codersdk.Client, opts ...func(*Deps)) (Deps, error) {
|
||||
d := Deps{
|
||||
coderClient: client,
|
||||
@@ -173,7 +193,7 @@ type ReportTaskArgs struct {
|
||||
|
||||
var ReportTask = Tool[ReportTaskArgs, codersdk.Response]{
|
||||
Tool: aisdk.Tool{
|
||||
Name: "coder_report_task",
|
||||
Name: ToolNameReportTask,
|
||||
Description: `Report progress on your work.
|
||||
|
||||
The user observes your work through a Task UI. To keep them updated
|
||||
@@ -238,7 +258,7 @@ type GetWorkspaceArgs struct {
|
||||
|
||||
var GetWorkspace = Tool[GetWorkspaceArgs, codersdk.Workspace]{
|
||||
Tool: aisdk.Tool{
|
||||
Name: "coder_get_workspace",
|
||||
Name: ToolNameGetWorkspace,
|
||||
Description: `Get a workspace by ID.
|
||||
|
||||
This returns more data than list_workspaces to reduce token usage.`,
|
||||
@@ -269,7 +289,7 @@ type CreateWorkspaceArgs struct {
|
||||
|
||||
var CreateWorkspace = Tool[CreateWorkspaceArgs, codersdk.Workspace]{
|
||||
Tool: aisdk.Tool{
|
||||
Name: "coder_create_workspace",
|
||||
Name: ToolNameCreateWorkspace,
|
||||
Description: `Create a new workspace in Coder.
|
||||
|
||||
If a user is asking to "test a template", they are typically referring
|
||||
@@ -331,7 +351,7 @@ type ListWorkspacesArgs struct {
|
||||
|
||||
var ListWorkspaces = Tool[ListWorkspacesArgs, []MinimalWorkspace]{
|
||||
Tool: aisdk.Tool{
|
||||
Name: "coder_list_workspaces",
|
||||
Name: ToolNameListWorkspaces,
|
||||
Description: "Lists workspaces for the authenticated user.",
|
||||
Schema: aisdk.Schema{
|
||||
Properties: map[string]any{
|
||||
@@ -373,7 +393,7 @@ var ListWorkspaces = Tool[ListWorkspacesArgs, []MinimalWorkspace]{
|
||||
|
||||
var ListTemplates = Tool[NoArgs, []MinimalTemplate]{
|
||||
Tool: aisdk.Tool{
|
||||
Name: "coder_list_templates",
|
||||
Name: ToolNameListTemplates,
|
||||
Description: "Lists templates for the authenticated user.",
|
||||
Schema: aisdk.Schema{
|
||||
Properties: map[string]any{},
|
||||
@@ -406,7 +426,7 @@ type ListTemplateVersionParametersArgs struct {
|
||||
|
||||
var ListTemplateVersionParameters = Tool[ListTemplateVersionParametersArgs, []codersdk.TemplateVersionParameter]{
|
||||
Tool: aisdk.Tool{
|
||||
Name: "coder_template_version_parameters",
|
||||
Name: ToolNameListTemplateVersionParams,
|
||||
Description: "Get the parameters for a template version. You can refer to these as workspace parameters to the user, as they are typically important for creating a workspace.",
|
||||
Schema: aisdk.Schema{
|
||||
Properties: map[string]any{
|
||||
@@ -432,7 +452,7 @@ var ListTemplateVersionParameters = Tool[ListTemplateVersionParametersArgs, []co
|
||||
|
||||
var GetAuthenticatedUser = Tool[NoArgs, codersdk.User]{
|
||||
Tool: aisdk.Tool{
|
||||
Name: "coder_get_authenticated_user",
|
||||
Name: ToolNameGetAuthenticatedUser,
|
||||
Description: "Get the currently authenticated user, similar to the `whoami` command.",
|
||||
Schema: aisdk.Schema{
|
||||
Properties: map[string]any{},
|
||||
@@ -452,7 +472,7 @@ type CreateWorkspaceBuildArgs struct {
|
||||
|
||||
var CreateWorkspaceBuild = Tool[CreateWorkspaceBuildArgs, codersdk.WorkspaceBuild]{
|
||||
Tool: aisdk.Tool{
|
||||
Name: "coder_create_workspace_build",
|
||||
Name: ToolNameCreateWorkspaceBuild,
|
||||
Description: "Create a new workspace build for an existing workspace. Use this to start, stop, or delete.",
|
||||
Schema: aisdk.Schema{
|
||||
Properties: map[string]any{
|
||||
@@ -502,7 +522,7 @@ type CreateTemplateVersionArgs struct {
|
||||
|
||||
var CreateTemplateVersion = Tool[CreateTemplateVersionArgs, codersdk.TemplateVersion]{
|
||||
Tool: aisdk.Tool{
|
||||
Name: "coder_create_template_version",
|
||||
Name: ToolNameCreateTemplateVersion,
|
||||
Description: `Create a new template version. This is a precursor to creating a template, or you can update an existing template.
|
||||
|
||||
Templates are Terraform defining a development environment. The provisioned infrastructure must run
|
||||
@@ -1002,7 +1022,7 @@ type GetWorkspaceAgentLogsArgs struct {
|
||||
|
||||
var GetWorkspaceAgentLogs = Tool[GetWorkspaceAgentLogsArgs, []string]{
|
||||
Tool: aisdk.Tool{
|
||||
Name: "coder_get_workspace_agent_logs",
|
||||
Name: ToolNameGetWorkspaceAgentLogs,
|
||||
Description: `Get the logs of a workspace agent.
|
||||
|
||||
More logs may appear after this call. It does not wait for the agent to finish.`,
|
||||
@@ -1041,7 +1061,7 @@ type GetWorkspaceBuildLogsArgs struct {
|
||||
|
||||
var GetWorkspaceBuildLogs = Tool[GetWorkspaceBuildLogsArgs, []string]{
|
||||
Tool: aisdk.Tool{
|
||||
Name: "coder_get_workspace_build_logs",
|
||||
Name: ToolNameGetWorkspaceBuildLogs,
|
||||
Description: `Get the logs of a workspace build.
|
||||
|
||||
Useful for checking whether a workspace builds successfully or not.`,
|
||||
@@ -1078,7 +1098,7 @@ type GetTemplateVersionLogsArgs struct {
|
||||
|
||||
var GetTemplateVersionLogs = Tool[GetTemplateVersionLogsArgs, []string]{
|
||||
Tool: aisdk.Tool{
|
||||
Name: "coder_get_template_version_logs",
|
||||
Name: ToolNameGetTemplateVersionLogs,
|
||||
Description: "Get the logs of a template version. This is useful to check whether a template version successfully imports or not.",
|
||||
Schema: aisdk.Schema{
|
||||
Properties: map[string]any{
|
||||
@@ -1115,7 +1135,7 @@ type UpdateTemplateActiveVersionArgs struct {
|
||||
|
||||
var UpdateTemplateActiveVersion = Tool[UpdateTemplateActiveVersionArgs, string]{
|
||||
Tool: aisdk.Tool{
|
||||
Name: "coder_update_template_active_version",
|
||||
Name: ToolNameUpdateTemplateActiveVersion,
|
||||
Description: "Update the active version of a template. This is helpful when iterating on templates.",
|
||||
Schema: aisdk.Schema{
|
||||
Properties: map[string]any{
|
||||
@@ -1154,7 +1174,7 @@ type UploadTarFileArgs struct {
|
||||
|
||||
var UploadTarFile = Tool[UploadTarFileArgs, codersdk.UploadResponse]{
|
||||
Tool: aisdk.Tool{
|
||||
Name: "coder_upload_tar_file",
|
||||
Name: ToolNameUploadTarFile,
|
||||
Description: `Create and upload a tar file by key/value mapping of file names to file contents. Use this to create template versions. Reference the tool description of "create_template_version" to understand template requirements.`,
|
||||
Schema: aisdk.Schema{
|
||||
Properties: map[string]any{
|
||||
@@ -1216,7 +1236,7 @@ type CreateTemplateArgs struct {
|
||||
|
||||
var CreateTemplate = Tool[CreateTemplateArgs, codersdk.Template]{
|
||||
Tool: aisdk.Tool{
|
||||
Name: "coder_create_template",
|
||||
Name: ToolNameCreateTemplate,
|
||||
Description: "Create a new template in Coder. First, you must create a template version.",
|
||||
Schema: aisdk.Schema{
|
||||
Properties: map[string]any{
|
||||
@@ -1269,7 +1289,7 @@ type DeleteTemplateArgs struct {
|
||||
|
||||
var DeleteTemplate = Tool[DeleteTemplateArgs, codersdk.Response]{
|
||||
Tool: aisdk.Tool{
|
||||
Name: "coder_delete_template",
|
||||
Name: ToolNameDeleteTemplate,
|
||||
Description: "Delete a template. This is irreversible.",
|
||||
Schema: aisdk.Schema{
|
||||
Properties: map[string]any{
|
||||
|
||||
Generated
+42
-2
@@ -1366,12 +1366,52 @@ This is required on creation to enable a user-flow of validating a template work
|
||||
## codersdk.CreateTestAuditLogRequest
|
||||
|
||||
```json
|
||||
{}
|
||||
{
|
||||
"action": "create",
|
||||
"additional_fields": [
|
||||
0
|
||||
],
|
||||
"build_reason": "autostart",
|
||||
"organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
|
||||
"request_id": "266ea41d-adf5-480b-af50-15b940c2b846",
|
||||
"resource_id": "4d5215ed-38bb-48ed-879a-fdb9ca58522f",
|
||||
"resource_type": "template",
|
||||
"time": "2019-08-24T14:15:22Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Properties
|
||||
|
||||
None
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
|---------------------|------------------------------------------------|----------|--------------|-------------|
|
||||
| `action` | [codersdk.AuditAction](#codersdkauditaction) | false | | |
|
||||
| `additional_fields` | array of integer | false | | |
|
||||
| `build_reason` | [codersdk.BuildReason](#codersdkbuildreason) | false | | |
|
||||
| `organization_id` | string | false | | |
|
||||
| `request_id` | string | false | | |
|
||||
| `resource_id` | string | false | | |
|
||||
| `resource_type` | [codersdk.ResourceType](#codersdkresourcetype) | false | | |
|
||||
| `time` | string | false | | |
|
||||
|
||||
#### Enumerated Values
|
||||
|
||||
| Property | Value |
|
||||
|-----------------|--------------------|
|
||||
| `action` | `create` |
|
||||
| `action` | `write` |
|
||||
| `action` | `delete` |
|
||||
| `action` | `start` |
|
||||
| `action` | `stop` |
|
||||
| `build_reason` | `autostart` |
|
||||
| `build_reason` | `autostop` |
|
||||
| `build_reason` | `initiator` |
|
||||
| `resource_type` | `template` |
|
||||
| `resource_type` | `template_version` |
|
||||
| `resource_type` | `user` |
|
||||
| `resource_type` | `workspace` |
|
||||
| `resource_type` | `workspace_build` |
|
||||
| `resource_type` | `git_ssh_key` |
|
||||
| `resource_type` | `auditable_group` |
|
||||
|
||||
## codersdk.CreateTokenRequest
|
||||
|
||||
|
||||
Reference in New Issue
Block a user