Implement flattened _meta format for server extensions (#331)

## Summary

This PR implements the flattened `_meta` format for server extensions as
discussed in #284, replacing the confusing wrapper format with a clean
single-file approach.

**Before (wrapper format):**
```json
{
  "server": { "name": "my-server", "description": "..." },
  "x-publisher": { "build_info": "..." },
  "x-io.modelcontextprotocol.registry": { "id": "...", "published_at": "..." }
}
```

**After (flattened format):**
```json
{
  "name": "my-server",
  "description": "...",
  "_meta": {
    "publisher": { "build_info": "..." },
    "io.modelcontextprotocol.registry": { "id": "...", "published_at": "..." }
  }
}
```

## Key Changes

- **Flattened Format**: Single `ServerJSON` file with structured `_meta`
field
- **Better DX**: Publishers maintain one file instead of separate
server.json + extensions.json
- **MCP Compliance**: Uses standard `_meta` mechanism instead of `x-*`
prefixes
- **Simplified Database**: PostgreSQL now uses simple `id, value` table
structure
- **Type Safety**: Structured `ServerMeta` with known extension fields

## Database Migration

Added migration `003_simplify_to_key_value.sql` that drops the complex
relational structure and creates a simple key-value table. This
significantly simplifies database management.

## Testing

- All core tests passing (validators, service layer)
- Schema validation working for all 10 examples
- Seed data successfully migrated (396 entries)
- Publishing functionality verified

Fixes #284
This commit is contained in:
adam jones 2025-09-01 19:27:23 +01:00 • committed by GitHub
commit 218b0b422d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -15,23 +15,29 @@ type RegistryExtensions struct {
ReleaseDate string `json:"release_date"`
}
// ServerRecord represents the unified storage and API response model
type ServerRecord struct {
Server model.ServerJSON `json:"server"` // Pure MCP server.json
XIOModelContextProtocolRegistry RegistryExtensions `json:"x-io.modelcontextprotocol.registry,omitempty"` // Registry-generated data
XPublisher map[string]interface{} `json:"x-publisher,omitempty"` // x-publisher extensions
}
// ServerListResponse represents the paginated server list response
type ServerListResponse struct {
Servers []ServerRecord `json:"servers"`
Metadata *Metadata `json:"metadata,omitempty"`
Servers []ServerJSON `json:"servers"`
Metadata *Metadata `json:"metadata,omitempty"`
}
// PublishRequest represents the API request format for publishing servers
type PublishRequest struct {
Server model.ServerJSON `json:"server"`
XPublisher map[string]interface{} `json:"x-publisher,omitempty"`
// ServerMeta represents the structured metadata with known extension fields
type ServerMeta struct {
Publisher map[string]interface{} `json:"publisher,omitempty"`
IOModelContextProtocolRegistry *RegistryExtensions `json:"io.modelcontextprotocol.registry,omitempty"`
}
// ServerJSON represents complete server information as defined in the MCP spec, with extension support
type ServerJSON struct {
Schema string `json:"$schema,omitempty"`
Name string `json:"name" minLength:"1" maxLength:"200"`
Description string `json:"description" minLength:"1" maxLength:"100"`
Status model.Status `json:"status,omitempty" minLength:"1"`
Repository model.Repository `json:"repository,omitempty"`
VersionDetail model.VersionDetail `json:"version_detail"`
Packages []model.Package `json:"packages,omitempty"`
Remotes []model.Remote `json:"remotes,omitempty"`
Meta *ServerMeta `json:"_meta,omitempty"`
}
// Metadata represents pagination metadata