Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ jobs:
run: |
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.4.0

- name: Prepare schema for embedding
run: make prep-schema

- name: Run lint
run: make lint

Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,7 @@ validate-schemas
coverage.out
coverage.html
deploy/infra/infra
registry
registry

# Generated schema directory for embedding
internal/validators/schema/
11 changes: 8 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@ help: ## Show this help message
@echo "Available targets:"
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " %-20s %s\n", $$1, $$2}'

# Preparation targets
prep-schema: ## Copy schema file for embedding
@mkdir -p internal/validators/schema
@cp docs/reference/server-json/server.schema.json internal/validators/schema/server.schema.json

# Build targets
build: ## Build the registry application with version info
build: prep-schema ## Build the registry application with version info
@mkdir -p bin
go build -ldflags="-X main.Version=dev-$(shell git rev-parse --short HEAD) -X main.GitCommit=$(shell git rev-parse HEAD) -X main.BuildTime=$(shell date -u +%Y-%m-%dT%H:%M:%SZ)" -o bin/registry ./cmd/registry

publisher: ## Build the publisher tool with version info
publisher: prep-schema ## Build the publisher tool with version info
@mkdir -p bin
go build -ldflags="-X main.Version=dev-$(shell git rev-parse --short HEAD) -X main.GitCommit=$(shell git rev-parse HEAD) -X main.BuildTime=$(shell date -u +%Y-%m-%dT%H:%M:%SZ)" -o bin/mcp-publisher ./cmd/publisher

Expand All @@ -26,7 +31,7 @@ check-schema: ## Check if server.schema.json is in sync with openapi.yaml
@./bin/extract-server-schema -check

# Test targets
test-unit: ## Run unit tests with coverage (requires PostgreSQL)
test-unit: prep-schema ## Run unit tests with coverage (requires PostgreSQL)
@echo "Starting PostgreSQL for unit tests..."
@docker compose up -d postgres
@echo "Waiting for PostgreSQL to be ready..."
Expand Down
10 changes: 9 additions & 1 deletion cmd/publisher/commands/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"strings"
"time"

"github.com/modelcontextprotocol/registry/internal/validators"
apiv0 "github.com/modelcontextprotocol/registry/pkg/api/v0"
"github.com/modelcontextprotocol/registry/pkg/model"
)
Expand Down Expand Up @@ -300,8 +301,15 @@ func createServerJSON(
}

// Create server structure
// Get current schema version from embedded schema
currentSchema, err := validators.GetCurrentSchemaVersion()
if err != nil {
// Should never happen (schema is embedded)
panic(fmt.Sprintf("failed to get embedded schema version: %v", err))
}

return apiv0.ServerJSON{
Schema: model.CurrentSchemaURL,
Schema: currentSchema,
Name: name,
Description: description,
Repository: model.Repository{
Expand Down
19 changes: 15 additions & 4 deletions cmd/publisher/commands/publish.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import (
"path/filepath"
"strings"

"github.com/modelcontextprotocol/registry/internal/validators"
apiv0 "github.com/modelcontextprotocol/registry/pkg/api/v0"
"github.com/modelcontextprotocol/registry/pkg/model"
)

func PublishCommand(args []string) error {
Expand All @@ -40,13 +40,24 @@ func PublishCommand(args []string) error {

// Check for deprecated schema and recommend migration
// Allow empty schema (will use default) but reject old schemas
if serverJSON.Schema != "" && !strings.Contains(serverJSON.Schema, model.CurrentSchemaVersion) {
return fmt.Errorf(`deprecated schema detected: %s.
if serverJSON.Schema != "" {
// Get current schema version from embedded schema
currentSchema, err := validators.GetCurrentSchemaVersion()
if err != nil {
// Schema is embedded, so this should never happen
return fmt.Errorf("failed to get current schema version: %w", err)
}

if serverJSON.Schema != currentSchema {
return fmt.Errorf(`deprecated schema detected: %s.

Expected current schema: %s

Migrate to the current schema format for new servers.

📋 Migration checklist: https://github.com/modelcontextprotocol/registry/blob/main/docs/reference/server-json/CHANGELOG.md#migration-checklist-for-publishers
📖 Full changelog with examples: https://github.com/modelcontextprotocol/registry/blob/main/docs/reference/server-json/CHANGELOG.md`, serverJSON.Schema)
📖 Full changelog with examples: https://github.com/modelcontextprotocol/registry/blob/main/docs/reference/server-json/CHANGELOG.md`, serverJSON.Schema, currentSchema)
}
}

// Load saved token
Expand Down
81 changes: 81 additions & 0 deletions cmd/publisher/commands/validate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package commands

import (
"encoding/json"
"fmt"
"os"
"strings"

"github.com/modelcontextprotocol/registry/internal/validators"
apiv0 "github.com/modelcontextprotocol/registry/pkg/api/v0"
)

func ValidateCommand(args []string) error {
// Parse arguments
serverFile := "server.json"

for _, arg := range args {
if !strings.HasPrefix(arg, "-") {
serverFile = arg
}
}

// Read server file
serverData, err := os.ReadFile(serverFile)
if err != nil {
if os.IsNotExist(err) {
return fmt.Errorf("%s not found, please check the file path", serverFile)
}
return fmt.Errorf("failed to read %s: %w", serverFile, err)
}

// Validate JSON
var serverJSON apiv0.ServerJSON
if err := json.Unmarshal(serverData, &serverJSON); err != nil {
return fmt.Errorf("invalid JSON: %w", err)
}

// Check for deprecated schema and recommend migration
// Allow empty schema (will use default) but reject old schemas
if serverJSON.Schema != "" {
// Get current schema version from embedded schema
currentSchema, err := validators.GetCurrentSchemaVersion()
if err != nil {
// Should never happen (schema is embedded)
return fmt.Errorf("failed to get current schema version: %w", err)
}

if serverJSON.Schema != currentSchema {
return fmt.Errorf(`deprecated schema detected: %s.

Expected current schema: %s

Migrate to the current schema format for new servers.

📋 Migration checklist: https://github.com/modelcontextprotocol/registry/blob/main/docs/reference/server-json/CHANGELOG.md#migration-checklist-for-publishers
📖 Full changelog with examples: https://github.com/modelcontextprotocol/registry/blob/main/docs/reference/server-json/CHANGELOG.md`, serverJSON.Schema, currentSchema)
}
}

// Run detailed validation (this is the whole point of the validate command)
// Include schema validation for comprehensive validation
result := validators.ValidateServerJSONExhaustive(&serverJSON, true)

if result.Valid {
_, _ = fmt.Fprintln(os.Stdout, "✅ server.json is valid")
return nil
}

// Print all issues
_, _ = fmt.Fprintf(os.Stdout, "❌ Validation failed with %d issue(s):\n\n", len(result.Issues))
for i, issue := range result.Issues {
_, _ = fmt.Fprintf(os.Stdout, "%d. [%s] %s (%s)\n", i+1, issue.Severity, issue.Path, issue.Type)
_, _ = fmt.Fprintf(os.Stdout, " %s\n", issue.Message)
if issue.Reference != "" {
_, _ = fmt.Fprintf(os.Stdout, " Reference: %s\n", issue.Reference)
}
_, _ = fmt.Fprintln(os.Stdout)
}

return fmt.Errorf("validation failed")
}
3 changes: 3 additions & 0 deletions cmd/publisher/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ func main() {
err = commands.LogoutCommand()
case "publish":
err = commands.PublishCommand(os.Args[2:])
case "validate":
err = commands.ValidateCommand(os.Args[2:])
case "--version", "-v", "version":
log.Printf("mcp-publisher %s (commit: %s, built: %s)", Version, GitCommit, BuildTime)
return
Expand Down Expand Up @@ -65,6 +67,7 @@ func printUsage() {
_, _ = fmt.Fprintln(os.Stdout, " login Authenticate with the registry")
_, _ = fmt.Fprintln(os.Stdout, " logout Clear saved authentication")
_, _ = fmt.Fprintln(os.Stdout, " publish Publish server.json to the registry")
_, _ = fmt.Fprintln(os.Stdout, " validate Validate server.json without publishing")
_, _ = fmt.Fprintln(os.Stdout)
_, _ = fmt.Fprintln(os.Stdout, "Use 'mcp-publisher <command> --help' for more information about a command.")
}
Loading
Loading