Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
4 changes: 2 additions & 2 deletions docs/guides/contributing/add-package-registry.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ The MCP Registry project is a **metaregistry**, meaning that it hosts metadata f

For local MCP servers, the MCP Registry has pointers in the `packages` node of the [`server.json`](../../reference/server-json/generic-server-json.md) schema that refer to packages in supported package managers.

The list of supported package managers for hosting MCP servers is defined by the `properties.packages[N].properties.registryType` string enum in the [`server.json` schema](../../reference/server-json/server.schema.json). For example, this could be "npm" (for npmjs.com packages) or "pypi" (for PyPI packages).
The list of supported package managers for hosting MCP servers is defined by the `properties.packages[N].properties.registryType` string enum in the [`server.json` schema](../../reference/server-json/server.schema.json). For example, this could be "npm" (for npmjs.com packages) or "pypi" (for PyPI packages). A special `on_device` value is also supported for pre-installed, system-managed servers that do not originate from a remote package registry.

For remote MCP servers, the package registry is not relevant. The MCP client consumes the server via a URL instead of by downloading and running a package. In other words, this document only applies to local MCP servers.

Expand Down Expand Up @@ -38,7 +38,7 @@ These steps may evolve as additional validations or details are discovered and m
- Add your package registry base url to the `registryBaseUrl` example array.
- Add the single-shot CLI command name to the `runtimeHint` example value array.
- Update the [`openapi.yaml`](../../reference/api/openapi.yaml)
- Add your package registry name to the `registryType` enum value array.
- Add your package registry name to the `registryType` enum value array (not needed for `on_device`, which is already defined).
- Add your package registry base url to the `registryBaseUrl` enum value array.
- Add the single-shot CLI command name to the `runtimeHint` example value array.
- Add a sample, minimal `server.json` to the [`server.json` examples](../../reference/server-json/generic-server-json.md).
Expand Down
10 changes: 9 additions & 1 deletion docs/reference/api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -275,13 +275,14 @@ components:
properties:
registryType:
type: string
description: Registry type indicating how to download packages (e.g., 'npm', 'pypi', 'oci', 'nuget', 'mcpb')
description: Registry type indicating how to download or locate packages (e.g., 'npm', 'pypi', 'oci', 'nuget', 'mcpb', 'on_device'). The 'on_device' type represents a pre-installed server that should be launched locally and not downloaded.
examples:
- "npm"
- "pypi"
- "oci"
- "nuget"
- "mcpb"
- "on_device"
registryBaseUrl:
type: string
format: uri
Expand Down Expand Up @@ -336,6 +337,13 @@ components:
description: A mapping of environment variables to be set when running the package.
items:
$ref: '#/components/schemas/KeyValueInput'
manifest:
type: object
description: Optional embedded MCPB manifest describing an on-device server. Only used when registryType is 'on_device'.
additionalProperties: true
__dirname:
type: string
description: Optional local directory path containing the on-device server implementation (analogous to Node.js __dirname). Only used when registryType is 'on_device'.

Input:
type: object
Expand Down
8 changes: 8 additions & 0 deletions docs/reference/server-json/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

Changes to the server.json schema and format.

## Unreleased

### Added
- Support for `on_device` `registryType` for pre-installed/system-managed MCP servers.
- New optional `manifest` field on package objects (used with `on_device`) to embed an MCPB-style manifest.
- New optional `__dirname` field on package objects to specify the local directory containing on-device server assets.


## 2025-09-29

### ⚠️ BREAKING CHANGES
Expand Down
46 changes: 46 additions & 0 deletions docs/reference/server-json/generic-server-json.md
Original file line number Diff line number Diff line change
Expand Up @@ -678,3 +678,49 @@ For MCP servers that follow a custom installation path or are embedded in applic
}
```

### On-Device (Pre-Installed) Server Example

Some platforms (e.g., an operating system distribution) may provide a catalog of pre-installed or system-managed MCP servers. These can be referenced using the `on_device` `registryType`. In this case, the server is not downloaded from a registry. Instead, the platform launches it using a known runtime or entry point. An embedded `manifest` can be provided (reusing the MCPB manifest format) along with an optional `__dirname` pointing to the local directory where related assets or binaries reside.

```json
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json",
"name": "com.example/troubleshooting",
"description": "On-device troubleshooting server provided by the OS",
"version": "1.0.0",
"packages": [
{
"registryType": "on_device",
"identifier": "com.example.troubleshooting",
"version": "1.0.0",
"runtimeHint": "odr.exe",
"transport": { "type": "stdio" },
"manifest": {
"manifest_version": "0.2",
"name": "troubleshooting-mcp-server",
"version": "1.0.0",
"description": "MCP server for OS troubleshooting utilities",
"author": { "name": "ExampleOS" },
"server": {
"type": "binary",
"entry_point": "C:\\Windows\\System32\\odr.exe",
"mcp_config": {
"command": "odr.exe",
"args": ["mcp", "--proxy", "troubleshooting-mcp-server"]
}
}
},
"__dirname": "C:\\Windows\\System32\\mcp\\troubleshooting"
}
]
}
```

Notes:

- `registryBaseUrl` is omitted because the package is not fetched remotely.
- `manifest` embeds the MCPB-style metadata so clients have consistent information without a download.
- `__dirname` gives clients a stable local path if they need to resolve relative resources (optional).
- Validation for `on_device` packages does not perform remote ownership checks; responsibility shifts to the platform distribution.


14 changes: 12 additions & 2 deletions docs/reference/server-json/server.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@
},
"Package": {
"properties": {
"__dirname": {
"description": "Optional local directory path containing the on-device server implementation (analogous to Node.js __dirname). Only used when registryType is 'on_device'.",
"type": "string"
},
"environmentVariables": {
"description": "A mapping of environment variables to be set when running the package.",
"items": {
Expand All @@ -213,6 +217,11 @@
],
"type": "string"
},
"manifest": {
"additionalProperties": true,
"description": "Optional embedded MCPB manifest describing an on-device server. Only used when registryType is 'on_device'.",
"type": "object"
},
"packageArguments": {
"description": "A list of arguments to be passed to the package's binary.",
"items": {
Expand All @@ -234,13 +243,14 @@
"type": "string"
},
"registryType": {
"description": "Registry type indicating how to download packages (e.g., 'npm', 'pypi', 'oci', 'nuget', 'mcpb')",
"description": "Registry type indicating how to download or locate packages (e.g., 'npm', 'pypi', 'oci', 'nuget', 'mcpb', 'on_device'). The 'on_device' type represents a pre-installed server that should be launched locally and not downloaded.",
"examples": [
"npm",
"pypi",
"oci",
"nuget",
"mcpb"
"mcpb",
"on_device"
],
"type": "string"
},
Expand Down
5 changes: 5 additions & 0 deletions internal/validators/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ func ValidatePackage(ctx context.Context, pkg model.Package, serverName string)
return registries.ValidateOCI(ctx, pkg, serverName)
case model.RegistryTypeMCPB:
return registries.ValidateMCPB(ctx, pkg, serverName)
case model.RegistryTypeOnDevice:
// On-device packages are assumed to be pre-installed and do not require
// remote registry validation. Basic structural validation (e.g., presence
// of identifier/version) is handled elsewhere. We simply accept them here.
return nil
default:
return fmt.Errorf("unsupported registry type: %s", pkg.RegistryType)
}
Expand Down
1 change: 1 addition & 0 deletions internal/validators/validators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1623,6 +1623,7 @@ func TestValidate_RegistryTypesAndUrls(t *testing.T) {
{"valid_mcpb_github", "io.github.domdomegg/airtable-mcp-server", model.RegistryTypeMCPB, "", "https://github.com/domdomegg/airtable-mcp-server/releases/download/v1.7.2/airtable-mcp-server.mcpb", "1.7.2", "fe333e598595000ae021bd27117db32ec69af6987f507ba7a63c90638ff633ce", false},
{"valid_mcpb_gitlab", "io.gitlab.fforster/gitlab-mcp", model.RegistryTypeMCPB, model.RegistryURLGitLab, "https://gitlab.com/fforster/gitlab-mcp/-/releases/v1.31.0/downloads/gitlab-mcp_1.31.0_Linux_x86_64.tar.gz", "1.31.0", "abc123ef4567890abcdef1234567890abcdef1234567890abcdef1234567890", false}, // this is not actually a valid mcpb, but it's the closest I can get for testing for now
{"valid_mcpb_gitlab", "io.gitlab.fforster/gitlab-mcp", model.RegistryTypeMCPB, "", "https://gitlab.com/fforster/gitlab-mcp/-/releases/v1.31.0/downloads/gitlab-mcp_1.31.0_Linux_x86_64.tar.gz", "1.31.0", "abc123ef4567890abcdef1234567890abcdef1234567890abcdef1234567890", false}, // this is not actually a valid mcpb, but it's the closest I can get for testing for now
{"valid_on_device", "io.github.domdomegg/airtable-mcp-server", model.RegistryTypeOnDevice, "", "airtable-mcp-server", "1.7.2", "", false},

// Test MCPB without file hash (should fail)
{"invalid_mcpb_no_hash", "io.github.domdomegg/airtable-mcp-server", model.RegistryTypeMCPB, model.RegistryURLGitHub, "https://github.com/domdomegg/airtable-mcp-server/releases/download/v1.7.2/airtable-mcp-server.mcpb", "1.7.2", "", true},
Expand Down
4 changes: 4 additions & 0 deletions pkg/model/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ const (
RegistryTypeOCI = "oci"
RegistryTypeNuGet = "nuget"
RegistryTypeMCPB = "mcpb"
// RegistryTypeOnDevice represents a package that is already available on the local device
// and should be launched using the provided runtimeHint / manifest configuration rather than
// being downloaded from a remote registry.
RegistryTypeOnDevice = "on_device"
)

// Registry Base URLs - supported package registry base URLs
Expand Down
4 changes: 4 additions & 0 deletions pkg/model/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ type Package struct {
RuntimeArguments []Argument `json:"runtimeArguments,omitempty"`
PackageArguments []Argument `json:"packageArguments,omitempty"`
EnvironmentVariables []KeyValueInput `json:"environmentVariables,omitempty"`
// Manifest is an optional embedded MCPB manifest describing an on-device server. Only used when registryType == on_device.
Manifest map[string]any `json:"manifest,omitempty"`
// Dirname is the directory on the local filesystem containing the on-device server (mirrors Node.js __dirname semantics for discovery). Only used when registryType == on_device.
Dirname string `json:"__dirname,omitempty"`
}

// Repository represents a source code repository as defined in the spec
Expand Down
2 changes: 1 addition & 1 deletion tools/validate-examples/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func main() {

func runValidation() error {
// Define what we validate and how
expectedServerJSONCount := 12
expectedServerJSONCount := 13
targets := []validationTarget{
{
path: filepath.Join("docs", "reference", "server-json", "generic-server-json.md"),
Expand Down
Loading