Enforce schema validation on the publish and edit API level (#598)
<!-- Provide a brief summary of your changes --> ## Motivation and Context <!-- Why is this change needed? What problem does it solve? --> The following PR: * Enforces schema validation on the API level (requests without schema or older schema will fail) * Updates the unit tests and examples to match that ## How Has This Been Tested? <!-- Have you tested this in a real application? Which scenarios were tested? --> ## Breaking Changes <!-- Will users need to update their code or configurations? --> **Note this can be considered breaking if clients have not included it before.** ## Types of changes <!-- What types of changes does your code introduce? Put an `x` in all the boxes that apply: --> - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update ## Checklist <!-- Go over all the following points, and put an `x` in all the boxes that apply. --> - [ ] I have read the [MCP Documentation](https://modelcontextprotocol.io) - [ ] My code follows the repository's style guidelines - [ ] New and existing tests pass locally - [ ] I have added appropriate error handling - [ ] I have added or updated documentation as needed ## Additional context <!-- Add any other context, implementation notes, or design decisions --> --------- Signed-off-by: Radoslav Dimitrov <radoslav@stacklok.com>
This commit is contained in:
parent
e0f30f1a29
commit
44950c23bb
15 changed files with 244 additions and 21 deletions
|
|
@ -301,7 +301,7 @@ func createServerJSON(
|
|||
|
||||
// Create server structure
|
||||
return apiv0.ServerJSON{
|
||||
Schema: "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json",
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: name,
|
||||
Description: description,
|
||||
Repository: model.Repository{
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import (
|
|||
"strings"
|
||||
|
||||
apiv0 "github.com/modelcontextprotocol/registry/pkg/api/v0"
|
||||
"github.com/modelcontextprotocol/registry/pkg/model"
|
||||
)
|
||||
|
||||
func PublishCommand(args []string) error {
|
||||
|
|
@ -39,8 +40,8 @@ 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, "2025-09-29") {
|
||||
return fmt.Errorf(`deprecated schema detected :%s.
|
||||
if serverJSON.Schema != "" && !strings.Contains(serverJSON.Schema, model.CurrentSchemaVersion) {
|
||||
return fmt.Errorf(`deprecated schema detected: %s.
|
||||
|
||||
Migrate to the current schema format for new servers.
|
||||
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ Suppose your MCP server application requires a `mcp start` CLI arguments to star
|
|||
|
||||
```json
|
||||
{
|
||||
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json",
|
||||
"name": "io.github.joelverhagen/knapcode-samplemcpserver",
|
||||
"description": "Sample NuGet MCP server for a random number and random weather",
|
||||
"version": "0.4.0-beta",
|
||||
|
|
@ -250,6 +251,7 @@ This will essentially instruct the MCP client to execute `dnx Knapcode.SampleMcp
|
|||
|
||||
```json
|
||||
{
|
||||
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json",
|
||||
"name": "io.modelcontextprotocol.anonymous/mcp-fs",
|
||||
"description": "Cloud-hosted MCP filesystem server",
|
||||
"repository": {
|
||||
|
|
@ -283,6 +285,7 @@ This will essentially instruct the MCP client to execute `dnx Knapcode.SampleMcp
|
|||
|
||||
```json
|
||||
{
|
||||
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json",
|
||||
"name": "io.github.example/weather-mcp",
|
||||
"description": "Python MCP server for weather data access",
|
||||
"repository": {
|
||||
|
|
@ -337,6 +340,7 @@ The `dnx` tool ships with the .NET 10 SDK, starting with Preview 6.
|
|||
|
||||
```json
|
||||
{
|
||||
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json",
|
||||
"name": "io.github.joelverhagen/knapcode-samplemcpserver",
|
||||
"description": "Sample NuGet MCP server for a random number and random weather",
|
||||
"repository": {
|
||||
|
|
@ -385,6 +389,7 @@ The `dnx` tool ships with the .NET 10 SDK, starting with Preview 6.
|
|||
|
||||
```json
|
||||
{
|
||||
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json",
|
||||
"name": "io.github.example/database-manager",
|
||||
"description": "MCP server for database operations with support for multiple database types",
|
||||
"repository": {
|
||||
|
|
@ -580,6 +585,7 @@ The `dnx` tool ships with the .NET 10 SDK, starting with Preview 6.
|
|||
|
||||
```json
|
||||
{
|
||||
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json",
|
||||
"name": "io.modelcontextprotocol/text-editor",
|
||||
"description": "MCP Bundle server for advanced text editing capabilities",
|
||||
"repository": {
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ func TestEditServerEndpoint(t *testing.T) {
|
|||
// Create test servers for different scenarios
|
||||
testServers := map[string]*apiv0.ServerJSON{
|
||||
"editable": {
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "io.github.testuser/editable-server",
|
||||
Description: "Server that can be edited",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -52,6 +53,7 @@ func TestEditServerEndpoint(t *testing.T) {
|
|||
},
|
||||
},
|
||||
"other": {
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "io.github.otheruser/other-server",
|
||||
Description: "Server owned by another user",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -71,6 +73,7 @@ func TestEditServerEndpoint(t *testing.T) {
|
|||
|
||||
// Create a deleted server for undelete testing
|
||||
deletedServer := &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "io.github.testuser/deleted-server",
|
||||
Description: "Server that was deleted",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -89,6 +92,7 @@ func TestEditServerEndpoint(t *testing.T) {
|
|||
|
||||
// Create a server with build metadata for URL encoding test
|
||||
buildMetadataServer := &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "io.github.testuser/build-metadata-server",
|
||||
Description: "Server with build metadata version",
|
||||
Version: "1.0.0+20130313144700",
|
||||
|
|
@ -125,6 +129,7 @@ func TestEditServerEndpoint(t *testing.T) {
|
|||
},
|
||||
},
|
||||
requestBody: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "io.github.testuser/editable-server",
|
||||
Description: "Updated server description",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -155,6 +160,7 @@ func TestEditServerEndpoint(t *testing.T) {
|
|||
},
|
||||
},
|
||||
requestBody: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "io.github.testuser/editable-server",
|
||||
Description: "Server with status change",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -182,6 +188,7 @@ func TestEditServerEndpoint(t *testing.T) {
|
|||
version: "1.0.0",
|
||||
authHeader: "InvalidFormat token123",
|
||||
requestBody: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "io.github.testuser/editable-server",
|
||||
Description: "Test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -195,6 +202,7 @@ func TestEditServerEndpoint(t *testing.T) {
|
|||
version: "1.0.0",
|
||||
authHeader: "Bearer invalid-token",
|
||||
requestBody: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "io.github.testuser/editable-server",
|
||||
Description: "Test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -214,6 +222,7 @@ func TestEditServerEndpoint(t *testing.T) {
|
|||
},
|
||||
},
|
||||
requestBody: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "io.github.testuser/editable-server",
|
||||
Description: "Updated test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -233,6 +242,7 @@ func TestEditServerEndpoint(t *testing.T) {
|
|||
},
|
||||
},
|
||||
requestBody: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "io.github.otheruser/other-server",
|
||||
Description: "Updated test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -252,6 +262,7 @@ func TestEditServerEndpoint(t *testing.T) {
|
|||
},
|
||||
},
|
||||
requestBody: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "io.github.testuser/non-existent",
|
||||
Description: "Non-existent server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -271,6 +282,7 @@ func TestEditServerEndpoint(t *testing.T) {
|
|||
},
|
||||
},
|
||||
requestBody: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "io.github.testuser/renamed-server", // Different name
|
||||
Description: "Trying to rename server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -290,6 +302,7 @@ func TestEditServerEndpoint(t *testing.T) {
|
|||
},
|
||||
},
|
||||
requestBody: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "io.github.testuser/editable-server",
|
||||
Description: "Version mismatch test",
|
||||
Version: "2.0.0", // Different version from URL
|
||||
|
|
@ -309,6 +322,7 @@ func TestEditServerEndpoint(t *testing.T) {
|
|||
},
|
||||
},
|
||||
requestBody: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "io.github.testuser/deleted-server",
|
||||
Description: "Trying to undelete server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -329,6 +343,7 @@ func TestEditServerEndpoint(t *testing.T) {
|
|||
},
|
||||
},
|
||||
requestBody: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "io.github.testuser/build-metadata-server",
|
||||
Description: "Updated server with build metadata",
|
||||
Version: "1.0.0+20130313144700",
|
||||
|
|
@ -432,6 +447,7 @@ func TestEditServerEndpointEdgeCases(t *testing.T) {
|
|||
|
||||
for _, server := range testServers {
|
||||
_, err := registryService.CreateServer(context.Background(), &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: server.name,
|
||||
Description: "Test server for editing",
|
||||
Version: server.version,
|
||||
|
|
@ -441,6 +457,7 @@ func TestEditServerEndpointEdgeCases(t *testing.T) {
|
|||
// Set specific status if not active
|
||||
if server.status != model.StatusActive {
|
||||
_, err = registryService.UpdateServer(context.Background(), server.name, server.version, &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: server.name,
|
||||
Description: "Test server for editing",
|
||||
Version: server.version,
|
||||
|
|
@ -498,6 +515,7 @@ func TestEditServerEndpointEdgeCases(t *testing.T) {
|
|||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
requestBody := apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: tt.serverName,
|
||||
Description: "Status transition test",
|
||||
Version: tt.version,
|
||||
|
|
@ -546,6 +564,7 @@ func TestEditServerEndpointEdgeCases(t *testing.T) {
|
|||
// Create server with special characters
|
||||
specialServerName := "io.dots.and-dashes/server_with_underscores"
|
||||
_, err := registryService.CreateServer(context.Background(), &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: specialServerName,
|
||||
Description: "Server with special characters",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -553,6 +572,7 @@ func TestEditServerEndpointEdgeCases(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
requestBody := apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: specialServerName,
|
||||
Description: "Updated server with special chars",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -593,6 +613,7 @@ func TestEditServerEndpointEdgeCases(t *testing.T) {
|
|||
t.Run("version-specific editing", func(t *testing.T) {
|
||||
// Test editing a specific version of a multi-version server
|
||||
requestBody := apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/multi-version-server",
|
||||
Description: "Updated v1.0.0 specifically",
|
||||
Version: "1.0.0",
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ func TestPublishIntegration(t *testing.T) {
|
|||
|
||||
t.Run("successful publish with GitHub auth", func(t *testing.T) {
|
||||
publishReq := apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "io.github.testuser/test-mcp-server",
|
||||
Description: "A test MCP server for integration testing",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -101,6 +102,7 @@ func TestPublishIntegration(t *testing.T) {
|
|||
|
||||
t.Run("successful publish with none auth (no prefix)", func(t *testing.T) {
|
||||
publishReq := apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-mcp-server-no-auth",
|
||||
Description: "A test MCP server without authentication",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -143,7 +145,8 @@ func TestPublishIntegration(t *testing.T) {
|
|||
|
||||
t.Run("publish fails with missing authorization header", func(t *testing.T) {
|
||||
publishReq := apiv0.ServerJSON{
|
||||
Name: "test-server",
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "test-server",
|
||||
}
|
||||
|
||||
body, err := json.Marshal(publishReq)
|
||||
|
|
@ -162,6 +165,7 @@ func TestPublishIntegration(t *testing.T) {
|
|||
|
||||
t.Run("publish fails with invalid token", func(t *testing.T) {
|
||||
publishReq := apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "io.github.domdomegg/test-server",
|
||||
Description: "Test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -183,6 +187,7 @@ func TestPublishIntegration(t *testing.T) {
|
|||
|
||||
t.Run("publish fails when permission denied", func(t *testing.T) {
|
||||
publishReq := apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "io.github.other/test-server",
|
||||
Description: "A test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -219,6 +224,7 @@ func TestPublishIntegration(t *testing.T) {
|
|||
|
||||
t.Run("publish succeeds with MCPB package", func(t *testing.T) {
|
||||
publishReq := apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "io.github.domdomegg/airtable-mcp-server",
|
||||
Description: "A test server with MCPB package",
|
||||
Version: "1.7.2",
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ func TestPublishRegistryValidation(t *testing.T) {
|
|||
|
||||
t.Run("publish fails with npm registry validation error", func(t *testing.T) {
|
||||
publishReq := apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server-with-npm",
|
||||
Description: "A test server with invalid npm package reference",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -86,6 +87,7 @@ func TestPublishRegistryValidation(t *testing.T) {
|
|||
|
||||
t.Run("publish succeeds with MCPB package (registry validation enabled)", func(t *testing.T) {
|
||||
publishReq := apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server-mcpb-validation",
|
||||
Description: "A test server with MCPB package and registry validation enabled",
|
||||
Version: "0.0.36",
|
||||
|
|
@ -136,6 +138,7 @@ func TestPublishRegistryValidation(t *testing.T) {
|
|||
|
||||
t.Run("publish fails when second package fails npm validation", func(t *testing.T) {
|
||||
publishReq := apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server-multiple-packages",
|
||||
Description: "A test server with multiple packages where second fails",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -187,6 +190,7 @@ func TestPublishRegistryValidation(t *testing.T) {
|
|||
|
||||
t.Run("publish fails when first package fails validation", func(t *testing.T) {
|
||||
publishReq := apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server-first-package-fails",
|
||||
Description: "A test server where first package fails",
|
||||
Version: "1.0.0",
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ func TestPublishEndpoint(t *testing.T) {
|
|||
{
|
||||
name: "successful publish with GitHub auth",
|
||||
requestBody: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "io.github.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -80,6 +81,7 @@ func TestPublishEndpoint(t *testing.T) {
|
|||
{
|
||||
name: "successful publish with no auth (AuthMethodNone)",
|
||||
requestBody: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "example/test-server",
|
||||
Description: "A test server without auth",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -113,6 +115,7 @@ func TestPublishEndpoint(t *testing.T) {
|
|||
{
|
||||
name: "invalid authorization header format",
|
||||
requestBody: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "io.github.domdomegg/test-server",
|
||||
Description: "Test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -127,6 +130,7 @@ func TestPublishEndpoint(t *testing.T) {
|
|||
{
|
||||
name: "invalid token",
|
||||
requestBody: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "test-server",
|
||||
Description: "A test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -141,6 +145,7 @@ func TestPublishEndpoint(t *testing.T) {
|
|||
{
|
||||
name: "permission denied",
|
||||
requestBody: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "io.github.other/test-server",
|
||||
Description: "A test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -165,6 +170,7 @@ func TestPublishEndpoint(t *testing.T) {
|
|||
{
|
||||
name: "registry service error",
|
||||
requestBody: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "example/test-server",
|
||||
Description: "A test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -183,6 +189,7 @@ func TestPublishEndpoint(t *testing.T) {
|
|||
setupRegistryService: func(registry service.RegistryService) {
|
||||
// Pre-publish the same server to cause duplicate version error
|
||||
existingServer := apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "example/test-server",
|
||||
Description: "Existing test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -200,6 +207,7 @@ func TestPublishEndpoint(t *testing.T) {
|
|||
{
|
||||
name: "package validation success - MCPB package",
|
||||
requestBody: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server-mcpb",
|
||||
Description: "A test server with MCPB package",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -227,6 +235,7 @@ func TestPublishEndpoint(t *testing.T) {
|
|||
{
|
||||
name: "invalid server name - multiple slashes (two slashes)",
|
||||
requestBody: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/server/path",
|
||||
Description: "Server with multiple slashes in name",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -249,6 +258,7 @@ func TestPublishEndpoint(t *testing.T) {
|
|||
{
|
||||
name: "invalid server name - multiple slashes (three slashes)",
|
||||
requestBody: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "org.company/dept/team/project",
|
||||
Description: "Server with three slashes in name",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -266,6 +276,7 @@ func TestPublishEndpoint(t *testing.T) {
|
|||
{
|
||||
name: "invalid server name - consecutive slashes",
|
||||
requestBody: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example//double-slash",
|
||||
Description: "Server with consecutive slashes",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -283,6 +294,7 @@ func TestPublishEndpoint(t *testing.T) {
|
|||
{
|
||||
name: "invalid server name - URL-like path",
|
||||
requestBody: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/servers/v1/api",
|
||||
Description: "Server with URL-like path structure",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -300,6 +312,7 @@ func TestPublishEndpoint(t *testing.T) {
|
|||
{
|
||||
name: "invalid server name - many slashes",
|
||||
requestBody: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "a/b/c/d/e/f",
|
||||
Description: "Server with many slashes",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -317,6 +330,7 @@ func TestPublishEndpoint(t *testing.T) {
|
|||
{
|
||||
name: "invalid server name - with packages and remotes",
|
||||
requestBody: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test/server/v2",
|
||||
Description: "Complex server with invalid name",
|
||||
Version: "2.0.0",
|
||||
|
|
@ -470,6 +484,7 @@ func TestPublishEndpoint_MultipleSlashesEdgeCases(t *testing.T) {
|
|||
|
||||
// Create request body
|
||||
requestBody := apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: tc.serverName,
|
||||
Description: "Test server",
|
||||
Version: "1.0.0",
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ func TestListServersEndpoint(t *testing.T) {
|
|||
|
||||
// Setup test data
|
||||
_, err := registryService.CreateServer(ctx, &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/server-alpha",
|
||||
Description: "Alpha test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -33,6 +34,7 @@ func TestListServersEndpoint(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
_, err = registryService.CreateServer(ctx, &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/server-beta",
|
||||
Description: "Beta test server",
|
||||
Version: "2.0.0",
|
||||
|
|
@ -118,6 +120,7 @@ func TestGetServerByNameEndpoint(t *testing.T) {
|
|||
|
||||
// Setup test data
|
||||
_, err := registryService.CreateServer(ctx, &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/detail-server",
|
||||
Description: "Server for detail testing",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -180,6 +183,7 @@ func TestGetServerVersionEndpoint(t *testing.T) {
|
|||
|
||||
// Setup test data with multiple versions
|
||||
_, err := registryService.CreateServer(ctx, &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: serverName,
|
||||
Description: "Version test server v1",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -187,6 +191,7 @@ func TestGetServerVersionEndpoint(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
_, err = registryService.CreateServer(ctx, &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: serverName,
|
||||
Description: "Version test server v2",
|
||||
Version: "2.0.0",
|
||||
|
|
@ -195,6 +200,7 @@ func TestGetServerVersionEndpoint(t *testing.T) {
|
|||
|
||||
// Add version with build metadata for URL encoding test
|
||||
_, err = registryService.CreateServer(ctx, &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: serverName,
|
||||
Description: "Version test server with build metadata",
|
||||
Version: "1.0.0+20130313144700",
|
||||
|
|
@ -304,6 +310,7 @@ func TestGetAllVersionsEndpoint(t *testing.T) {
|
|||
versions := []string{"1.0.0", "1.1.0", "2.0.0"}
|
||||
for _, version := range versions {
|
||||
_, err := registryService.CreateServer(ctx, &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: serverName,
|
||||
Description: "Multi-version test server " + version,
|
||||
Version: version,
|
||||
|
|
@ -402,6 +409,7 @@ func TestServersEndpointEdgeCases(t *testing.T) {
|
|||
|
||||
for _, server := range specialServers {
|
||||
_, err := registryService.CreateServer(ctx, &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: server.name,
|
||||
Description: server.description,
|
||||
Version: server.version,
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import (
|
|||
func TestPrometheusHandler(t *testing.T) {
|
||||
registryService := service.NewRegistryService(database.NewTestDB(t), config.NewConfig())
|
||||
server, err := registryService.CreateServer(context.Background(), &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "io.github.example/test-server",
|
||||
Description: "Test server detail",
|
||||
Repository: model.Repository{
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ func TestImportService_LocalFile(t *testing.T) {
|
|||
tempFile := "/tmp/test_import_seed.json"
|
||||
seedData := []*apiv0.ServerJSON{
|
||||
{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "io.github.test/test-server-1",
|
||||
Description: "Test server 1",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -65,6 +66,7 @@ func TestImportService_HTTPFile(t *testing.T) {
|
|||
// Create a test HTTP server
|
||||
seedData := []*apiv0.ServerJSON{
|
||||
{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "io.github.test/http-test-server",
|
||||
Description: "HTTP test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -115,11 +117,13 @@ func TestImportService_RegistryPagination(t *testing.T) {
|
|||
// Setup source registry with test data
|
||||
sourceServers := []*apiv0.ServerJSON{
|
||||
{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.source/server-1",
|
||||
Description: "Source server 1",
|
||||
Version: "1.0.0",
|
||||
},
|
||||
{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.source/server-2",
|
||||
Description: "Source server 2",
|
||||
Version: "1.0.0",
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ func TestValidateNoDuplicateRemoteURLs(t *testing.T) {
|
|||
// Create test data
|
||||
existingServers := map[string]*apiv0.ServerJSON{
|
||||
"existing1": {
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/existing-server",
|
||||
Description: "An existing server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -31,6 +32,7 @@ func TestValidateNoDuplicateRemoteURLs(t *testing.T) {
|
|||
},
|
||||
},
|
||||
"existing2": {
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.microsoft/another-server",
|
||||
Description: "Another existing server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -58,6 +60,7 @@ func TestValidateNoDuplicateRemoteURLs(t *testing.T) {
|
|||
{
|
||||
name: "no remote URLs - should pass",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/new-server",
|
||||
Description: "A new server with no remotes",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -68,6 +71,7 @@ func TestValidateNoDuplicateRemoteURLs(t *testing.T) {
|
|||
{
|
||||
name: "new unique remote URLs - should pass",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/new-server-unique",
|
||||
Description: "A new server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -81,6 +85,7 @@ func TestValidateNoDuplicateRemoteURLs(t *testing.T) {
|
|||
{
|
||||
name: "duplicate remote URL - should fail",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/new-server-duplicate",
|
||||
Description: "A new server with duplicate URL",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -94,6 +99,7 @@ func TestValidateNoDuplicateRemoteURLs(t *testing.T) {
|
|||
{
|
||||
name: "updating same server with same URLs - should pass",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/existing-server", // Same name as existing
|
||||
Description: "Updated existing server",
|
||||
Version: "1.1.0", // Different version
|
||||
|
|
@ -128,6 +134,7 @@ func TestGetServerByName(t *testing.T) {
|
|||
|
||||
// Create multiple versions of the same server
|
||||
_, err := service.CreateServer(ctx, &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "Test server v1",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -135,6 +142,7 @@ func TestGetServerByName(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
_, err = service.CreateServer(ctx, &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "Test server v2",
|
||||
Version: "2.0.0",
|
||||
|
|
@ -197,6 +205,7 @@ func TestGetServerByNameAndVersion(t *testing.T) {
|
|||
|
||||
// Create multiple versions of the same server
|
||||
_, err := service.CreateServer(ctx, &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: serverName,
|
||||
Description: "Versioned server v1",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -204,6 +213,7 @@ func TestGetServerByNameAndVersion(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
_, err = service.CreateServer(ctx, &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: serverName,
|
||||
Description: "Versioned server v2",
|
||||
Version: "2.0.0",
|
||||
|
|
@ -288,6 +298,7 @@ func TestGetAllVersionsByServerName(t *testing.T) {
|
|||
|
||||
// Create multiple versions of the same server
|
||||
_, err := service.CreateServer(ctx, &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: serverName,
|
||||
Description: "Multi-version server v1",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -295,6 +306,7 @@ func TestGetAllVersionsByServerName(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
_, err = service.CreateServer(ctx, &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: serverName,
|
||||
Description: "Multi-version server v2",
|
||||
Version: "2.0.0",
|
||||
|
|
@ -302,6 +314,7 @@ func TestGetAllVersionsByServerName(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
_, err = service.CreateServer(ctx, &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: serverName,
|
||||
Description: "Multi-version server v2.1",
|
||||
Version: "2.1.0",
|
||||
|
|
@ -388,6 +401,7 @@ func TestCreateServerConcurrentVersionsNoRace(t *testing.T) {
|
|||
go func(idx int) {
|
||||
defer wg.Done()
|
||||
result, err := service.CreateServer(ctx, &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: serverName,
|
||||
Description: fmt.Sprintf("Version %d", idx),
|
||||
Version: fmt.Sprintf("1.0.%d", idx),
|
||||
|
|
@ -437,6 +451,7 @@ func TestUpdateServer(t *testing.T) {
|
|||
|
||||
// Create initial server
|
||||
_, err := service.CreateServer(ctx, &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: serverName,
|
||||
Description: "Original description",
|
||||
Version: version,
|
||||
|
|
@ -461,6 +476,7 @@ func TestUpdateServer(t *testing.T) {
|
|||
serverName: serverName,
|
||||
version: version,
|
||||
updatedServer: &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: serverName,
|
||||
Description: "Updated description",
|
||||
Version: version,
|
||||
|
|
@ -482,6 +498,7 @@ func TestUpdateServer(t *testing.T) {
|
|||
serverName: serverName,
|
||||
version: version,
|
||||
updatedServer: &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: serverName,
|
||||
Description: "Updated with status change",
|
||||
Version: version,
|
||||
|
|
@ -499,6 +516,7 @@ func TestUpdateServer(t *testing.T) {
|
|||
serverName: "com.example/non-existent",
|
||||
version: "1.0.0",
|
||||
updatedServer: &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/non-existent",
|
||||
Description: "Should fail",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -540,6 +558,7 @@ func TestUpdateServer_SkipValidationForDeletedServers(t *testing.T) {
|
|||
|
||||
// Create server with invalid package configuration (this would fail registry validation)
|
||||
invalidServer := &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: serverName,
|
||||
Description: "Server with invalid package for testing validation skip",
|
||||
Version: version,
|
||||
|
|
@ -572,6 +591,7 @@ func TestUpdateServer_SkipValidationForDeletedServers(t *testing.T) {
|
|||
|
||||
// Now try to update a deleted server - validation should be skipped
|
||||
updatedInvalidServer := &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: serverName,
|
||||
Description: "Updated description for deleted server",
|
||||
Version: version,
|
||||
|
|
@ -594,6 +614,7 @@ func TestUpdateServer_SkipValidationForDeletedServers(t *testing.T) {
|
|||
|
||||
// Test updating a server being set to deleted status
|
||||
activeServer := &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/being-deleted-test",
|
||||
Description: "Server being deleted",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -639,6 +660,7 @@ func TestListServers(t *testing.T) {
|
|||
|
||||
for _, server := range testServers {
|
||||
_, err := service.CreateServer(ctx, &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: server.name,
|
||||
Description: server.description,
|
||||
Version: server.version,
|
||||
|
|
@ -736,6 +758,7 @@ func TestVersionComparison(t *testing.T) {
|
|||
time.Sleep(v.delay)
|
||||
}
|
||||
_, err := service.CreateServer(ctx, &apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: serverName,
|
||||
Description: v.description,
|
||||
Version: v.version,
|
||||
|
|
|
|||
|
|
@ -53,6 +53,16 @@ var (
|
|||
)
|
||||
|
||||
func ValidateServerJSON(serverJSON *apiv0.ServerJSON) error {
|
||||
// Validate schema version is provided and supported
|
||||
// Note: Schema field is also marked as required in the ServerJSON struct definition
|
||||
// for API-level validation and documentation
|
||||
if serverJSON.Schema == "" {
|
||||
return fmt.Errorf("$schema field is required")
|
||||
}
|
||||
if !strings.Contains(serverJSON.Schema, model.CurrentSchemaVersion) {
|
||||
return fmt.Errorf("schema version %s is not supported. Please use schema version %s", serverJSON.Schema, model.CurrentSchemaVersion)
|
||||
}
|
||||
|
||||
// Validate server name exists and format
|
||||
if _, err := parseServerName(*serverJSON); err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -19,9 +19,51 @@ func TestValidate(t *testing.T) {
|
|||
serverDetail apiv0.ServerJSON
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
name: "Schema version is required",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
URL: "https://github.com/owner/repo",
|
||||
Source: "github",
|
||||
},
|
||||
Version: "1.0.0",
|
||||
},
|
||||
expectedError: "$schema field is required",
|
||||
},
|
||||
{
|
||||
name: "Schema version rejects old schema (2025-01-27)",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: "https://static.modelcontextprotocol.io/schemas/2025-01-27/server.schema.json",
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
URL: "https://github.com/owner/repo",
|
||||
Source: "github",
|
||||
},
|
||||
Version: "1.0.0",
|
||||
},
|
||||
expectedError: "schema version https://static.modelcontextprotocol.io/schemas/2025-01-27/server.schema.json is not supported",
|
||||
},
|
||||
{
|
||||
name: "Schema version accepts current schema (2025-09-29)",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
URL: "https://github.com/owner/repo",
|
||||
Source: "github",
|
||||
},
|
||||
Version: "1.0.0",
|
||||
},
|
||||
expectedError: "",
|
||||
},
|
||||
{
|
||||
name: "Version rejects top-level version ranges",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -35,6 +77,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "rejects package version ranges",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -56,6 +99,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "Version allows specific versions (semver)",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -77,6 +121,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "Version allows specific non-semver versions",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -98,6 +143,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "Version rejects wildcard and x-range",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -111,6 +157,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "Version rejects wildcard *",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -124,6 +171,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "Version allows freeform version with hyphen not a range",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -137,6 +185,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "Version rejects hyphen range of two versions",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -150,6 +199,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "Version rejects OR range with two versions",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -163,6 +213,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "Version rejects comparator with space",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -177,6 +228,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "server name with two slashes",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/server/path",
|
||||
Description: "A test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -186,6 +238,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "server name with three slashes",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/server/path/deep",
|
||||
Description: "A test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -195,6 +248,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "valid server detail with all fields",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -226,6 +280,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "server with invalid repository source",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -239,6 +294,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "server with invalid GitHub URL format",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -252,6 +308,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "server with invalid GitLab URL format",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -265,6 +322,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "server with valid repository subfolder",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -279,6 +337,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "server with repository subfolder containing path traversal",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -293,6 +352,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "server with repository subfolder starting with slash",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -307,6 +367,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "server with repository subfolder ending with slash",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -321,6 +382,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "server with repository subfolder containing invalid characters",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -335,6 +397,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "server with repository subfolder containing empty segments",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -349,6 +412,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "server with valid websiteUrl",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -363,6 +427,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "server with invalid websiteUrl - no scheme",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -377,6 +442,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "server with invalid websiteUrl - invalid scheme",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -391,6 +457,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "server with malformed websiteUrl",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -405,6 +472,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "server with websiteUrl that matches namespace domain",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -419,6 +487,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "server with websiteUrl subdomain that matches namespace",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -433,6 +502,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "server with websiteUrl that does not match namespace",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -447,6 +517,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "package with spaces in name",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -470,6 +541,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "package with reserved version 'latest'",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -494,6 +566,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "multiple packages with one invalid",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -525,6 +598,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "remote with invalid URL",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -544,6 +618,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "remote with missing scheme",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -563,6 +638,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "remote with localhost url",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -582,6 +658,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "remote with localhost url with port",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -601,6 +678,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "multiple remotes with one invalid",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -624,6 +702,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "server detail with nil packages and remotes",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -639,6 +718,7 @@ func TestValidate(t *testing.T) {
|
|||
{
|
||||
name: "server detail with empty packages and remotes slices",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -677,7 +757,8 @@ func TestValidate_RemoteNamespaceMatch(t *testing.T) {
|
|||
{
|
||||
name: "valid match - example.com domain",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Name: "com.example/test-server",
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Remotes: []model.Transport{
|
||||
{
|
||||
Type: "streamable-http",
|
||||
|
|
@ -690,7 +771,8 @@ func TestValidate_RemoteNamespaceMatch(t *testing.T) {
|
|||
{
|
||||
name: "valid match - subdomain mcp.example.com",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Name: "com.example/test-server",
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Remotes: []model.Transport{
|
||||
{
|
||||
Type: "streamable-http",
|
||||
|
|
@ -703,7 +785,8 @@ func TestValidate_RemoteNamespaceMatch(t *testing.T) {
|
|||
{
|
||||
name: "valid match - api subdomain",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Name: "com.example/api-server",
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/api-server",
|
||||
Remotes: []model.Transport{
|
||||
{
|
||||
Type: "streamable-http",
|
||||
|
|
@ -716,7 +799,8 @@ func TestValidate_RemoteNamespaceMatch(t *testing.T) {
|
|||
{
|
||||
name: "invalid - wrong domain",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Name: "com.example/test-server",
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Remotes: []model.Transport{
|
||||
{
|
||||
Type: "streamable-http",
|
||||
|
|
@ -730,7 +814,8 @@ func TestValidate_RemoteNamespaceMatch(t *testing.T) {
|
|||
{
|
||||
name: "invalid - different domain entirely",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Name: "com.microsoft/server",
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.microsoft/server",
|
||||
Remotes: []model.Transport{
|
||||
{
|
||||
Type: "streamable-http",
|
||||
|
|
@ -744,7 +829,8 @@ func TestValidate_RemoteNamespaceMatch(t *testing.T) {
|
|||
{
|
||||
name: "invalid URL format",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Name: "com.example/test",
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test",
|
||||
Remotes: []model.Transport{
|
||||
{
|
||||
Type: "streamable-http",
|
||||
|
|
@ -758,6 +844,7 @@ func TestValidate_RemoteNamespaceMatch(t *testing.T) {
|
|||
{
|
||||
name: "empty remotes array",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test",
|
||||
Remotes: []model.Transport{},
|
||||
},
|
||||
|
|
@ -766,7 +853,8 @@ func TestValidate_RemoteNamespaceMatch(t *testing.T) {
|
|||
{
|
||||
name: "multiple valid remotes - different subdomains",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Name: "com.example/server",
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/server",
|
||||
Remotes: []model.Transport{
|
||||
{
|
||||
Type: "streamable-http",
|
||||
|
|
@ -783,7 +871,8 @@ func TestValidate_RemoteNamespaceMatch(t *testing.T) {
|
|||
{
|
||||
name: "one valid, one invalid remote",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Name: "com.example/server",
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/server",
|
||||
Remotes: []model.Transport{
|
||||
{
|
||||
Type: "streamable-http",
|
||||
|
|
@ -824,21 +913,24 @@ func TestValidate_ServerNameFormat(t *testing.T) {
|
|||
{
|
||||
name: "valid namespace/name format",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Name: "com.example.api/server",
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example.api/server",
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "valid complex namespace",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Name: "com.microsoft.azure.service/webapp-server",
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.microsoft.azure.service/webapp-server",
|
||||
},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "empty server name",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Name: "",
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "",
|
||||
},
|
||||
expectError: true,
|
||||
errorMsg: "server name is required",
|
||||
|
|
@ -846,7 +938,8 @@ func TestValidate_ServerNameFormat(t *testing.T) {
|
|||
{
|
||||
name: "missing slash separator",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Name: "com.example.server",
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example.server",
|
||||
},
|
||||
expectError: true,
|
||||
errorMsg: "server name must be in format 'dns-namespace/name'",
|
||||
|
|
@ -854,7 +947,8 @@ func TestValidate_ServerNameFormat(t *testing.T) {
|
|||
{
|
||||
name: "empty namespace part",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Name: "/server-name",
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "/server-name",
|
||||
},
|
||||
expectError: true,
|
||||
errorMsg: "non-empty namespace and name parts",
|
||||
|
|
@ -862,7 +956,8 @@ func TestValidate_ServerNameFormat(t *testing.T) {
|
|||
{
|
||||
name: "empty name part",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Name: "com.example/",
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/",
|
||||
},
|
||||
expectError: true,
|
||||
errorMsg: "non-empty namespace and name parts",
|
||||
|
|
@ -870,7 +965,8 @@ func TestValidate_ServerNameFormat(t *testing.T) {
|
|||
{
|
||||
name: "multiple slashes - should be rejected",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Name: "com.example/server/path",
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/server/path",
|
||||
},
|
||||
expectError: true,
|
||||
errorMsg: "server name cannot contain multiple slashes",
|
||||
|
|
@ -955,7 +1051,8 @@ func TestValidate_MultipleSlashesInServerName(t *testing.T) {
|
|||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
serverDetail := apiv0.ServerJSON{
|
||||
Name: tt.serverName,
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: tt.serverName,
|
||||
}
|
||||
err := validators.ValidateServerJSON(&serverDetail)
|
||||
|
||||
|
|
@ -1173,6 +1270,7 @@ func TestValidate_TransportValidation(t *testing.T) {
|
|||
{
|
||||
name: "package transport stdio without URL should pass",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -1191,6 +1289,7 @@ func TestValidate_TransportValidation(t *testing.T) {
|
|||
{
|
||||
name: "package transport stdio with URL (should fail)",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -1211,6 +1310,7 @@ func TestValidate_TransportValidation(t *testing.T) {
|
|||
{
|
||||
name: "package transport streamable-http with valid URL",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -1230,6 +1330,7 @@ func TestValidate_TransportValidation(t *testing.T) {
|
|||
{
|
||||
name: "package transport streamable-http with templated URL",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -1253,6 +1354,7 @@ func TestValidate_TransportValidation(t *testing.T) {
|
|||
{
|
||||
name: "package transport streamable-http without URL",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -1271,6 +1373,7 @@ func TestValidate_TransportValidation(t *testing.T) {
|
|||
{
|
||||
name: "package transport streamable-http with templated URL missing variables",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -1292,6 +1395,7 @@ func TestValidate_TransportValidation(t *testing.T) {
|
|||
{
|
||||
name: "package transport sse with valid URL",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -1311,6 +1415,7 @@ func TestValidate_TransportValidation(t *testing.T) {
|
|||
{
|
||||
name: "package transport sse without URL",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -1330,6 +1435,7 @@ func TestValidate_TransportValidation(t *testing.T) {
|
|||
{
|
||||
name: "package transport unsupported type",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -1349,6 +1455,7 @@ func TestValidate_TransportValidation(t *testing.T) {
|
|||
{
|
||||
name: "remote transport streamable-http with valid URL",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -1364,6 +1471,7 @@ func TestValidate_TransportValidation(t *testing.T) {
|
|||
{
|
||||
name: "remote transport streamable-http without URL",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -1379,6 +1487,7 @@ func TestValidate_TransportValidation(t *testing.T) {
|
|||
{
|
||||
name: "remote transport sse with valid URL",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -1394,6 +1503,7 @@ func TestValidate_TransportValidation(t *testing.T) {
|
|||
{
|
||||
name: "remote transport sse without URL",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -1409,6 +1519,7 @@ func TestValidate_TransportValidation(t *testing.T) {
|
|||
{
|
||||
name: "remote transport stdio not supported",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -1423,6 +1534,7 @@ func TestValidate_TransportValidation(t *testing.T) {
|
|||
{
|
||||
name: "remote transport unsupported type",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -1439,6 +1551,7 @@ func TestValidate_TransportValidation(t *testing.T) {
|
|||
{
|
||||
name: "package transport allows localhost URLs",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -1458,6 +1571,7 @@ func TestValidate_TransportValidation(t *testing.T) {
|
|||
{
|
||||
name: "remote transport rejects localhost URLs",
|
||||
serverDetail: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Version: "1.0.0",
|
||||
|
|
@ -1530,6 +1644,7 @@ func TestValidate_RegistryTypesAndUrls(t *testing.T) {
|
|||
for _, tc := range testCases {
|
||||
t.Run(tc.tcName, func(t *testing.T) {
|
||||
serverJSON := apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: tc.name,
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
@ -1566,6 +1681,7 @@ func TestValidate_RegistryTypesAndUrls(t *testing.T) {
|
|||
|
||||
func createValidServerWithArgument(arg model.Argument) apiv0.ServerJSON {
|
||||
return apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "com.example/test-server",
|
||||
Description: "A test server",
|
||||
Repository: model.Repository{
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ type ServerMeta struct {
|
|||
|
||||
// ServerJSON represents complete server information as defined in the MCP spec, with extension support
|
||||
type ServerJSON struct {
|
||||
Schema string `json:"$schema,omitempty"`
|
||||
Schema string `json:"$schema" required:"true" minLength:"1"`
|
||||
Name string `json:"name" minLength:"1" maxLength:"200"`
|
||||
Description string `json:"description" minLength:"1" maxLength:"100"`
|
||||
Repository model.Repository `json:"repository,omitempty"`
|
||||
|
|
|
|||
|
|
@ -34,3 +34,11 @@ const (
|
|||
RuntimeHintDocker = "docker"
|
||||
RuntimeHintDNX = "dnx"
|
||||
)
|
||||
|
||||
// Schema versions
|
||||
const (
|
||||
// CurrentSchemaVersion is the current supported schema version date
|
||||
CurrentSchemaVersion = "2025-09-29"
|
||||
// CurrentSchemaURL is the full URL to the current schema
|
||||
CurrentSchemaURL = "https://static.modelcontextprotocol.io/schemas/" + CurrentSchemaVersion + "/server.schema.json"
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue