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

@ -59,7 +59,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/ServerResponse'
$ref: '#/components/schemas/ServerDetail'
'404':
description: Server not found
content:
@ -81,54 +81,54 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/PublishRequest'
$ref: '#/components/schemas/ServerDetail'
examples:
basic_server:
summary: Basic server with NPM package
value:
server:
name: "io.modelcontextprotocol/filesystem"
description: "Node.js server implementing Model Context Protocol (MCP) for filesystem operations."
status: "active"
repository:
url: "https://github.com/modelcontextprotocol/servers"
source: "github"
version_detail:
name: "io.modelcontextprotocol/filesystem"
description: "Node.js server implementing Model Context Protocol (MCP) for filesystem operations."
status: "active"
repository:
url: "https://github.com/modelcontextprotocol/servers"
source: "github"
version_detail:
version: "1.0.2"
packages:
- registry_type: "npm"
registry_base_url: "https://registry.npmjs.org"
identifier: "@modelcontextprotocol/server-filesystem"
version: "1.0.2"
packages:
- registry_type: "npm"
registry_base_url: "https://registry.npmjs.org"
identifier: "@modelcontextprotocol/server-filesystem"
version: "1.0.2"
x-publisher:
tool: "publisher-cli"
version: "1.2.3"
build_info:
commit: "abc123def456"
timestamp: "2023-12-01T10:30:00Z"
_meta:
publisher:
tool: "publisher-cli"
version: "1.2.3"
build_info:
commit: "abc123def456"
timestamp: "2023-12-01T10:30:00Z"
example_org_server:
summary: Server with example.com organization extensions
value:
server:
name: "com.example/demo-server"
description: "Example MCP server demonstrating publisher extensions."
status: "active"
repository:
url: "https://github.com/example/mcp-demo"
source: "github"
version_detail:
name: "com.example/demo-server"
description: "Example MCP server demonstrating publisher extensions."
status: "active"
repository:
url: "https://github.com/example/mcp-demo"
source: "github"
version_detail:
version: "1.0.0"
packages:
- registry_type: "npm"
registry_base_url: "https://registry.npmjs.org"
identifier: "@example/mcp-demo-server"
version: "1.0.0"
packages:
- registry_type: "npm"
registry_base_url: "https://registry.npmjs.org"
identifier: "@example/mcp-demo-server"
version: "1.0.0"
x-publisher:
contact_email: "maintainer@example.com"
build_metadata:
commit: "abc123"
timestamp: "2024-01-15T10:30:00Z"
x-com.example:
_meta:
publisher:
contact_email: "maintainer@example.com"
build_metadata:
commit: "abc123"
timestamp: "2024-01-15T10:30:00Z"
com.example:
marketplace_icon: "https://example.com/icon.png"
category: ["software_development"]
documentation_url: "https://docs.example.org"
@ -139,7 +139,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/ServerResponse'
$ref: '#/components/schemas/ServerDetail'
'401':
description: Unauthorized - Invalid or missing authentication token
content:
@ -261,7 +261,7 @@ components:
servers:
type: array
items:
$ref: '#/components/schemas/ServerResponse'
$ref: '#/components/schemas/ServerDetail'
metadata:
type: object
properties:
@ -484,82 +484,53 @@ components:
type: array
items:
$ref: '#/components/schemas/Remote'
ServerResponse:
description: API response format for MCP servers, including registry metadata and publisher extensions
type: object
required:
- server
- x-io.modelcontextprotocol.registry
properties:
server:
$ref: '#/components/schemas/ServerDetail'
description: The core MCP server specification
x-io.modelcontextprotocol.registry:
type: object
description: Registry-specific metadata managed by the MCP registry system
required:
- id
- published_at
- updated_at
- is_latest
properties:
id:
type: string
format: uuid
description: Unique registry identifier for this server entry
example: "550e8400-e29b-41d4-a716-446655440000"
published_at:
type: string
format: date-time
description: Timestamp when the server was first published to the registry
example: "2023-12-01T10:30:00Z"
updated_at:
type: string
format: date-time
description: Timestamp when the server entry was last updated
example: "2023-12-01T11:00:00Z"
is_latest:
type: boolean
description: Whether this is the latest version of the server
example: true
release_date:
type: string
format: date-time
description: Release date of the server version
example: "2023-12-01T10:30:00Z"
additionalProperties: false
x-publisher:
type: object
description: Publisher-specific metadata and build information attached during publishing
additionalProperties: true
example:
tool: "publisher-cli"
version: "1.2.3"
build_info:
commit: "abc123def456"
timestamp: "2023-12-01T10:30:00Z"
pipeline_id: "build-789"
additionalProperties: false
PublishRequest:
description: Request format for publishing MCP servers to the registry
type: object
required:
- server
properties:
server:
$ref: '#/components/schemas/ServerDetail'
description: The MCP server specification to publish
x-publisher:
type: object
description: Publisher-specific metadata and build information
additionalProperties: true
example:
tool: "publisher-cli"
version: "1.2.3"
build_info:
commit: "abc123def456"
timestamp: "2023-12-01T10:30:00Z"
pipeline_id: "build-789"
additionalProperties: false
_meta:
type: object
description: Extension metadata using reverse DNS namespacing
properties:
publisher:
type: object
description: Publisher-specific metadata and build information
additionalProperties: true
example:
tool: "publisher-cli"
version: "1.2.3"
build_info:
commit: "abc123def456"
timestamp: "2023-12-01T10:30:00Z"
pipeline_id: "build-789"
io.modelcontextprotocol.registry:
type: object
description: Registry-specific metadata managed by the MCP registry system
required:
- id
- published_at
- updated_at
- is_latest
properties:
id:
type: string
format: uuid
description: Unique registry identifier for this server entry
example: "550e8400-e29b-41d4-a716-446655440000"
published_at:
type: string
format: date-time
description: Timestamp when the server was first published to the registry
example: "2023-12-01T10:30:00Z"
updated_at:
type: string
format: date-time
description: Timestamp when the server entry was last updated
example: "2023-12-01T11:00:00Z"
is_latest:
type: boolean
description: Whether this is the latest version of the server
example: true
release_date:
type: string
format: date-time
description: Release date of the server version
example: "2023-12-01T10:30:00Z"
additionalProperties: false
additionalProperties: true