From e0e51eae37f3215f97537e7822d23ffcdcf73ee9 Mon Sep 17 00:00:00 2001 From: Radoslav Dimitrov Date: Fri, 5 Sep 2025 23:07:08 +0300 Subject: [PATCH] Reflect the latest registry changes in openapi.yaml (#345) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Motivation and Context The following PR: * Adds a new `transport` type used in Package and Remotes * Added `docker` to the `runtime_hint` examples * Added support for templated URLs. It is available for streamable-http and sse transports for Packages. I didn't thought of reasons to have this for Remotes, but we can enable it if needed. * Added validation for templated URLs so we can ensure all referenced placeholder variables are available. * For streamable-http and SSE transport types the URL is now a required property * Updated the publisher init command to reflect these changes * Updated the seed.json file * Added unit tests for the transport type related changes * Updated the server.json schema and the external pkg structs to reflect the new transport type * Updated the examples Thanks to @kkkarthik for spotting it! 🙏 ## How Has This Been Tested? Ran the tests locally ## Breaking Changes Yes ## Types of changes - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [x] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update ## Checklist - [ ] 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 --------- Signed-off-by: Radoslav Dimitrov --- cmd/publisher/commands/init.go | 3 + data/seed.json | 808 +++++++++--------- docs/server-json/examples.md | 38 +- docs/server-json/server.schema.json | 86 +- .../handlers/v0/publish_integration_test.go | 3 + .../v0/publish_registry_validation_test.go | 18 + internal/api/handlers/v0/publish_test.go | 3 + internal/service/registry_service_test.go | 26 +- internal/validators/utils.go | 106 ++- internal/validators/validators.go | 88 +- internal/validators/validators_test.go | 483 ++++++++++- pkg/api/v0/types.go | 2 +- pkg/model/types.go | 16 +- 13 files changed, 1192 insertions(+), 488 deletions(-) diff --git a/cmd/publisher/commands/init.go b/cmd/publisher/commands/init.go index 40e0c28..638ec51 100644 --- a/cmd/publisher/commands/init.go +++ b/cmd/publisher/commands/init.go @@ -294,6 +294,9 @@ func createServerJSON( Identifier: packageIdentifier, Version: packageVersion, EnvironmentVariables: envVars, + Transport: model.Transport{ + Type: model.TransportTypeStdio, + }, } // Create server structure diff --git a/data/seed.json b/data/seed.json index 6f3b16c..d282f8c 100644 --- a/data/seed.json +++ b/data/seed.json @@ -23,7 +23,7 @@ "registry_type": "npm", "identifier": "@21st-dev/magic", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -85,7 +85,7 @@ "registry_type": "pypi", "identifier": "adfinmcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -122,7 +122,7 @@ "registry_type": "npm", "identifier": "agentql-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -170,7 +170,7 @@ "registry_type": "npm", "identifier": "agentrpc", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -252,7 +252,7 @@ "registry_type": "pypi", "identifier": "mcp-aiven", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -326,7 +326,7 @@ "registry_type": "pypi", "identifier": "adb-mysql-mcp-server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -367,7 +367,7 @@ "registry_type": "pypi", "identifier": "alibaba-cloud-ops-mcp-server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -445,7 +445,7 @@ "registry_type": "pypi", "identifier": "iotdb-mcp-server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -476,7 +476,7 @@ "registry_type": "oci", "identifier": "apache/iotdb", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -525,7 +525,7 @@ "registry_type": "npm", "identifier": "@apify/actors-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -562,7 +562,7 @@ "registry_type": "oci", "identifier": "apimatic-validator---mcp", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -593,7 +593,7 @@ "registry_type": "pypi", "identifier": "arize-phoenix", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -624,7 +624,7 @@ "registry_type": "npm", "identifier": "@datastax/astra-db-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -669,7 +669,7 @@ "registry_type": "npm", "identifier": "mcp-audiense-insights", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -706,7 +706,7 @@ "registry_type": "npm", "identifier": "@bankless/onchain-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -764,7 +764,7 @@ "registry_type": "oci", "identifier": "bicscan-mcp", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -832,7 +832,7 @@ "registry_type": "oci", "identifier": "bitrise-mcp", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -873,7 +873,7 @@ "registry_type": "pypi", "identifier": "mcp-server-box", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -904,7 +904,7 @@ "registry_type": "pypi", "identifier": "chroma-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -945,7 +945,7 @@ "registry_type": "npm", "identifier": "@circleci/mcp-server-circleci", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -1025,7 +1025,7 @@ "registry_type": "pypi", "identifier": "mcp-clickhouse", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -1067,16 +1067,16 @@ "registry_type": "npm", "identifier": "@cloudflare/mcp-server-cloudflare", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "remotes": [ { - "transport_type": "sse", + "type": "sse", "url": "https://observability.mcp.cloudflare.com/sse" }, { - "transport_type": "sse", + "type": "sse", "url": "https://bindings.mcp.cloudflare.com/sse" } ], @@ -1118,7 +1118,7 @@ "registry_type": "npm", "identifier": "@codacy/codacy-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -1149,7 +1149,7 @@ "registry_type": "pypi", "identifier": "codelogic-mcp-server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -1236,7 +1236,7 @@ "registry_type": "oci", "identifier": "test-opik-mcp", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -1306,7 +1306,7 @@ "registry_type": "pypi", "identifier": "mcp-couchbase", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -1382,7 +1382,7 @@ "registry_type": "oci", "identifier": "dart-mcp-server", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -1413,7 +1413,7 @@ "registry_type": "pypi", "identifier": "devhub-cms-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -1444,7 +1444,7 @@ "registry_type": "npm", "identifier": "@dynatrace-oss/dynatrace-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -1475,7 +1475,7 @@ "registry_type": "oci", "identifier": "e2b-mcp-root", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -1512,7 +1512,7 @@ "registry_type": "npm", "identifier": "@edgee/mcp-server-edgee", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -1616,7 +1616,7 @@ "registry_type": "oci", "identifier": "@edubase/mcp", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -1668,7 +1668,7 @@ "registry_type": "npm", "identifier": "@elastic/mcp-server-elasticsearch", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -1699,7 +1699,7 @@ "registry_type": "pypi", "identifier": "mcp-server-esignatures", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -1748,7 +1748,7 @@ "registry_type": "npm", "identifier": "exa-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -1785,7 +1785,7 @@ "registry_type": "pypi", "identifier": "fewsats-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -1857,7 +1857,7 @@ "registry_type": "pypi", "identifier": "fibery-mcp-server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -1898,7 +1898,7 @@ "registry_type": "pypi", "identifier": "mcp-server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -1929,7 +1929,7 @@ "registry_type": "npm", "identifier": "firecrawl-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -1960,7 +1960,7 @@ "registry_type": "pypi", "identifier": "todos", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -2001,7 +2001,7 @@ "registry_type": "npm", "identifier": "@gleanwork/mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -2088,7 +2088,7 @@ "registry_type": "oci", "identifier": "@notainc/gyazo-mcp-server", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -2125,7 +2125,7 @@ "registry_type": "npm", "identifier": "@gotohuman/mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -2224,7 +2224,7 @@ "registry_type": "oci", "identifier": "grafana/mcp-grafana", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -2269,7 +2269,7 @@ "registry_type": "npm", "identifier": "graphlit-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -2318,7 +2318,7 @@ "registry_type": "pypi", "identifier": "greptimedb-mcp-server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -2349,7 +2349,7 @@ "registry_type": "npm", "identifier": "@heroku/mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -2402,7 +2402,7 @@ "registry_type": "pypi", "identifier": "hologres-mcp-server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -2439,7 +2439,7 @@ "registry_type": "npm", "identifier": "hyperbrowser-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -2470,7 +2470,7 @@ "registry_type": "npm", "identifier": "inbox-zero", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -2545,7 +2545,7 @@ "registry_type": "pypi", "identifier": "inkeep-mcp-server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -2586,7 +2586,7 @@ "registry_type": "npm", "identifier": "@integration-app/mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -2623,7 +2623,7 @@ "registry_type": "npm", "identifier": "@jetbrains/mcp-proxy", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -2685,7 +2685,7 @@ "registry_type": "pypi", "identifier": "kagimcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -2757,7 +2757,7 @@ "registry_type": "pypi", "identifier": "keboola-mcp-server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -2838,7 +2838,7 @@ "registry_type": "oci", "identifier": "@translated/lara-mcp", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -2891,7 +2891,7 @@ "registry_type": "pypi", "identifier": "logfire-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -2936,7 +2936,7 @@ "registry_type": "oci", "identifier": "mcp-server-langfuse", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -2967,7 +2967,7 @@ "registry_type": "oci", "identifier": "@lingo.dev", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -3012,7 +3012,7 @@ "registry_type": "npm", "identifier": "@makehq/mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -3043,7 +3043,7 @@ "registry_type": "pypi", "identifier": "meilisearch-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -3074,7 +3074,7 @@ "registry_type": "pypi", "identifier": "mcp-memgraph", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -3136,7 +3136,7 @@ "registry_type": "pypi", "identifier": "mcp-server-milvus", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -3181,7 +3181,7 @@ "registry_type": "npm", "identifier": "@gomomento/mcp-momento", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -3234,7 +3234,7 @@ "registry_type": "npm", "identifier": "mongodb-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -3306,7 +3306,7 @@ "registry_type": "pypi", "identifier": "mcp-server-motherduck", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -3363,7 +3363,7 @@ "registry_type": "pypi", "identifier": "needle-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -3414,7 +3414,7 @@ "registry_type": "npm", "identifier": "@neondatabase/mcp-server-neon", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -3445,7 +3445,7 @@ "registry_type": "oci", "identifier": "mcp-oceanbase", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -3482,7 +3482,7 @@ "registry_type": "npm", "identifier": "octagon-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -3544,7 +3544,7 @@ "registry_type": "pypi", "identifier": "oxylabs-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -3596,7 +3596,7 @@ "registry_type": "npm", "identifier": "@paddle/paddle-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -3633,7 +3633,7 @@ "registry_type": "npm", "identifier": "ppl-ai", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -3664,7 +3664,7 @@ "registry_type": "npm", "identifier": "@pinecone-database/mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -3754,7 +3754,7 @@ "registry_type": "oci", "identifier": "pinecone-io/assistant-mcp", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -3803,7 +3803,7 @@ "registry_type": "npm", "identifier": "@ragieai/mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -3840,7 +3840,7 @@ "registry_type": "npm", "identifier": "redis-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -3913,7 +3913,7 @@ "registry_type": "oci", "identifier": "mcp-redis-cloud", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -4027,7 +4027,7 @@ "registry_type": "oci", "identifier": "mcp-server-qdrant", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -4111,7 +4111,7 @@ "registry_type": "pypi", "identifier": "ramp-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -4148,7 +4148,7 @@ "registry_type": "npm", "identifier": "@raygun.io/mcp-server-raygun", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -4191,7 +4191,7 @@ "registry_type": "npm", "identifier": "@getrember/mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -4228,7 +4228,7 @@ "registry_type": "npm", "identifier": "riza-io", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -4265,7 +4265,7 @@ "registry_type": "npm", "identifier": "search1api-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -4313,7 +4313,7 @@ "registry_type": "npm", "identifier": "screenshotone-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -4344,7 +4344,7 @@ "registry_type": "pypi", "identifier": "semgrep-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -4395,7 +4395,7 @@ "registry_type": "pypi", "identifier": "singlestore_mcp_server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -4432,7 +4432,7 @@ "registry_type": "npm", "identifier": "tavily-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -4463,7 +4463,7 @@ "registry_type": "npm", "identifier": "tianji", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -4494,7 +4494,7 @@ "registry_type": "pypi", "identifier": "mcp-tinybird", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -4546,7 +4546,7 @@ "registry_type": "pypi", "identifier": "uns_mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -4599,7 +4599,7 @@ "registry_type": "npm", "identifier": "@vectorize-io/vectorize-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -4651,7 +4651,7 @@ "registry_type": "npm", "identifier": "verodat-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -4682,7 +4682,7 @@ "registry_type": "oci", "identifier": "veyrax-mcp", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -4734,7 +4734,7 @@ "registry_type": "npm", "identifier": "@xeroapi/xero-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -4802,7 +4802,7 @@ "registry_type": "pypi", "identifier": "zenml-io", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -4833,7 +4833,7 @@ "registry_type": "pypi", "identifier": "ableton-live-mcp-server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -4864,7 +4864,7 @@ "registry_type": "pypi", "identifier": "ableton-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -4906,7 +4906,7 @@ "registry_type": "npm", "identifier": "@openbnb/mcp-server-airbnb", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -4947,7 +4947,7 @@ "registry_type": "pypi", "identifier": "ai-agent-marketplace-index-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -4978,7 +4978,7 @@ "registry_type": "npm", "identifier": "algorand-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -5044,7 +5044,7 @@ "registry_type": "pypi", "identifier": "mcp-server-apache-airflow", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -5081,7 +5081,7 @@ "registry_type": "npm", "identifier": "airtable-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -5129,7 +5129,7 @@ "registry_type": "npm", "identifier": "@felores/airtable-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -5160,7 +5160,7 @@ "registry_type": "pypi", "identifier": "alphavantage", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -5191,7 +5191,7 @@ "registry_type": "pypi", "identifier": "mcp-amadeus", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -5301,7 +5301,7 @@ "registry_type": "pypi", "identifier": "mcp-server-gravitino", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -5342,7 +5342,7 @@ "registry_type": "pypi", "identifier": "mcp-ical", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -5373,7 +5373,7 @@ "registry_type": "npm", "identifier": "mcp-server-applescript", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -5425,7 +5425,7 @@ "registry_type": "oci", "identifier": "aranet4-mcp-server", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -5474,7 +5474,7 @@ "registry_type": "npm", "identifier": "arango-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -5505,7 +5505,7 @@ "registry_type": "oci", "identifier": "choturoboserver", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -5536,12 +5536,12 @@ "registry_type": "pypi", "identifier": "mcp-atlassian", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "remotes": [ { - "transport_type": "sse", + "type": "sse", "url": "http://localhost:9000/sse" } ], @@ -5573,7 +5573,7 @@ "registry_type": "oci", "identifier": "attestable-mcp-server", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -5604,7 +5604,7 @@ "registry_type": "oci", "identifier": "mcp-server-aws", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -5657,7 +5657,7 @@ "registry_type": "npm", "identifier": "@lishenxydlgzs/aws-athena-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -5735,7 +5735,7 @@ "registry_type": "pypi", "identifier": "aws-cost-explorer-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -5815,7 +5815,7 @@ "registry_type": "oci", "identifier": "mcp-server-aws-resources", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -5846,7 +5846,7 @@ "registry_type": "npm", "identifier": "s3-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -5980,7 +5980,7 @@ "registry_type": "oci", "identifier": "adx_mcp_server", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -6011,7 +6011,7 @@ "registry_type": "pypi", "identifier": "mcp-azure-devops", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -6048,7 +6048,7 @@ "registry_type": "npm", "identifier": "baidubce", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -6089,7 +6089,7 @@ "registry_type": "npm", "identifier": "@magnetai/free-usdc-transfer", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -6130,7 +6130,7 @@ "registry_type": "pypi", "identifier": "basic-memory", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -6161,7 +6161,7 @@ "registry_type": "pypi", "identifier": "mcp-server-bigquery", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -6224,7 +6224,7 @@ "registry_type": "npm", "identifier": "@ergut/mcp-bigquery-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -6261,7 +6261,7 @@ "registry_type": "oci", "identifier": "mcp_server_bing", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -6314,7 +6314,7 @@ "registry_type": "pypi", "identifier": "bitable-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -6363,7 +6363,7 @@ "registry_type": "pypi", "identifier": "blender-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -6394,7 +6394,7 @@ "registry_type": "npm", "identifier": "@agree-able/room-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -6471,7 +6471,7 @@ "registry_type": "pypi", "identifier": "browser-use-mcp-server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -6502,7 +6502,7 @@ "registry_type": "npm", "identifier": "bnbchain-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -6533,7 +6533,7 @@ "registry_type": "pypi", "identifier": "mcp-server-calculator", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -6584,7 +6584,7 @@ "registry_type": "pypi", "identifier": "cfbd-mcp-server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -6626,7 +6626,7 @@ "registry_type": "oci", "identifier": "aiql-desktop", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -6663,7 +6663,7 @@ "registry_type": "oci", "identifier": "mcp-server-chatsum", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -6715,7 +6715,7 @@ "registry_type": "pypi", "identifier": "chess_mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -6767,7 +6767,7 @@ "registry_type": "pypi", "identifier": "chroma", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -6819,7 +6819,7 @@ "registry_type": "pypi", "identifier": "email_client", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -6868,7 +6868,7 @@ "registry_type": "npm", "identifier": "@taazkareem/clickup-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -6924,7 +6924,7 @@ "registry_type": "npm", "identifier": "@felores/cloudinary-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -6966,7 +6966,7 @@ "registry_type": "oci", "identifier": "code_execution_server", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -6997,7 +6997,7 @@ "registry_type": "oci", "identifier": "consul-mcp", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -7028,7 +7028,7 @@ "registry_type": "pypi", "identifier": "cognee", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -7077,7 +7077,7 @@ "registry_type": "oci", "identifier": "coin-api-mcp", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -7108,7 +7108,7 @@ "registry_type": "npm", "identifier": "@shinzolabs/coinmarketcap-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -7190,7 +7190,7 @@ "registry_type": "oci", "identifier": "mcp_remote_macos_use", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -7243,7 +7243,7 @@ "registry_type": "npm", "identifier": "@ivotoby/contentful-management-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -7274,7 +7274,7 @@ "registry_type": "pypi", "identifier": "crypto-feargreed-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -7322,7 +7322,7 @@ "registry_type": "npm", "identifier": "crypto-indicators-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -7359,7 +7359,7 @@ "registry_type": "npm", "identifier": "crypto-sentiment-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -7390,7 +7390,7 @@ "registry_type": "pypi", "identifier": "cryptopanic-mcp-server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -7427,7 +7427,7 @@ "registry_type": "pypi", "identifier": "dappier-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -7510,7 +7510,7 @@ "registry_type": "npm", "identifier": "datadog-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -7541,7 +7541,7 @@ "registry_type": "pypi", "identifier": "mcp-server-ds", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -7572,7 +7572,7 @@ "registry_type": "pypi", "identifier": "samuelgursky", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -7613,7 +7613,7 @@ "registry_type": "pypi", "identifier": "dataset-viewer", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -7713,7 +7713,7 @@ "registry_type": "npm", "identifier": "deebo-prototype", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -7744,7 +7744,7 @@ "registry_type": "oci", "identifier": "mcp-server-deep-research", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -7781,7 +7781,7 @@ "registry_type": "npm", "identifier": "deepseek-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -7818,7 +7818,7 @@ "registry_type": "pypi", "identifier": "deepseek_r1", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -7859,7 +7859,7 @@ "registry_type": "npm", "identifier": "deepseek-thinker-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -7900,7 +7900,7 @@ "registry_type": "oci", "identifier": "descope-mcp-server", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -7931,7 +7931,7 @@ "registry_type": "pypi", "identifier": "devrev-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -7992,7 +7992,7 @@ "registry_type": "pypi", "identifier": "dicom-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -8054,7 +8054,7 @@ "registry_type": "pypi", "identifier": "dify-mcp-server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -8085,7 +8085,7 @@ "registry_type": "pypi", "identifier": "discord-mcp-server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -8133,7 +8133,7 @@ "registry_type": "npm", "identifier": "SaseQ", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -8178,7 +8178,7 @@ "registry_type": "npm", "identifier": "@ashdev/discourse-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -8209,7 +8209,7 @@ "registry_type": "pypi", "identifier": "mcp-server-docker", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -8240,7 +8240,7 @@ "registry_type": "oci", "identifier": "mcp-dblp", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -8271,7 +8271,7 @@ "registry_type": "oci", "identifier": "Omedia/mcp-server-drupal", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -8302,7 +8302,7 @@ "registry_type": "pypi", "identifier": "dune-analytics-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -8333,7 +8333,7 @@ "registry_type": "npm", "identifier": "edgeone-pages-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -8364,7 +8364,7 @@ "registry_type": "npm", "identifier": "edwin-sdk", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -8446,7 +8446,7 @@ "registry_type": "pypi", "identifier": "elevenlabs-mcp-server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -8477,7 +8477,7 @@ "registry_type": "pypi", "identifier": "mcp-server-email", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -8508,7 +8508,7 @@ "registry_type": "oci", "identifier": "eunomia-mcp-server", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -8539,12 +8539,12 @@ "registry_type": "npm", "identifier": "@mcpdotdirect/evm-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "remotes": [ { - "transport_type": "sse", + "type": "sse", "url": "http://localhost:3001/sse" } ], @@ -8603,7 +8603,7 @@ "registry_type": "pypi", "identifier": "mcp-server-everything-search", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -8640,12 +8640,12 @@ "registry_type": "pypi", "identifier": "excel-mcp-server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "remotes": [ { - "transport_type": "sse", + "type": "sse", "url": "http://localhost:8000/sse" } ], @@ -8677,7 +8677,7 @@ "registry_type": "pypi", "identifier": "fpl-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -8718,7 +8718,7 @@ "registry_type": "npm", "identifier": "fastn", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -8755,7 +8755,7 @@ "registry_type": "npm", "identifier": "fred-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -8786,7 +8786,7 @@ "registry_type": "pypi", "identifier": "fetch", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -8838,7 +8838,7 @@ "registry_type": "npm", "identifier": "figma-developer-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -8869,7 +8869,7 @@ "registry_type": "npm", "identifier": "@gannonh/firebase-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -8900,7 +8900,7 @@ "registry_type": "npm", "identifier": "firecrawl-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -8941,7 +8941,7 @@ "registry_type": "npm", "identifier": "flightradar24-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -8972,7 +8972,7 @@ "registry_type": "pypi", "identifier": "freqtrade-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -9017,7 +9017,7 @@ "registry_type": "npm", "identifier": "@fanyangmeng/ghost-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -9065,7 +9065,7 @@ "registry_type": "npm", "identifier": "github-actions-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -9106,7 +9106,7 @@ "registry_type": "npm", "identifier": "@ddukbg/github-enterprise-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -9137,7 +9137,7 @@ "registry_type": "npm", "identifier": "@gongrzhe/server-gmail-autoauth-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -9215,7 +9215,7 @@ "registry_type": "oci", "identifier": "mcp-server-headless-gmail", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -9246,7 +9246,7 @@ "registry_type": "npm", "identifier": "goalstory-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -9277,7 +9277,7 @@ "registry_type": "npm", "identifier": "goat-repo", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -9314,7 +9314,7 @@ "registry_type": "oci", "identifier": "godot-mcp", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -9365,7 +9365,7 @@ "registry_type": "oci", "identifier": "mark3labs/mcp-filesystem-server", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -9427,7 +9427,7 @@ "registry_type": "oci", "identifier": "mcp-goodnews", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -9458,7 +9458,7 @@ "registry_type": "pypi", "identifier": "googlecalendar", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -9489,7 +9489,7 @@ "registry_type": "pypi", "identifier": "google-calendar-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -9520,7 +9520,7 @@ "registry_type": "npm", "identifier": "@adenot/mcp-google-search", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -9572,7 +9572,7 @@ "registry_type": "pypi", "identifier": "mcp-google-sheets", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -9614,7 +9614,7 @@ "registry_type": "pypi", "identifier": "backend", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -9645,7 +9645,7 @@ "registry_type": "oci", "identifier": "mcp-vertexai-search", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -9687,7 +9687,7 @@ "registry_type": "npm", "identifier": "mcp-graphql-schema", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -9728,7 +9728,7 @@ "registry_type": "npm", "identifier": "@horizondatawave/mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -9759,7 +9759,7 @@ "registry_type": "oci", "identifier": "mesh-mcp-server", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -9796,7 +9796,7 @@ "registry_type": "npm", "identifier": "heurist-agent-framework", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -9837,7 +9837,7 @@ "registry_type": "npm", "identifier": "holaspirit-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -9868,7 +9868,7 @@ "registry_type": "oci", "identifier": "homeassistant-mcp", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -9958,7 +9958,7 @@ "registry_type": "oci", "identifier": "hass-mcp", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -10039,7 +10039,7 @@ "registry_type": "oci", "identifier": "mcp-server-hubspot", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -10119,7 +10119,7 @@ "registry_type": "npm", "identifier": "@llmindset/mcp-hfspace", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -10150,7 +10150,7 @@ "registry_type": "npm", "identifier": "@mektigboy/server-hyperliquid", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -10231,7 +10231,7 @@ "registry_type": "pypi", "identifier": "stefanoamorelli", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -10289,7 +10289,7 @@ "registry_type": "oci", "identifier": "ifly-workflow-mcp-server", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -10330,7 +10330,7 @@ "registry_type": "npm", "identifier": "@gongrzhe/image-gen-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -10375,7 +10375,7 @@ "registry_type": "npm", "identifier": "influxdb-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -10406,7 +10406,7 @@ "registry_type": "npm", "identifier": "@inoyu/mcp-unomi-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -10443,7 +10443,7 @@ "registry_type": "oci", "identifier": "mcp-server-for-intercom", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -10474,7 +10474,7 @@ "registry_type": "oci", "identifier": "mcp-server-simulator-ios-idb", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -10505,7 +10505,7 @@ "registry_type": "npm", "identifier": "iterm-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -10536,7 +10536,7 @@ "registry_type": "npm", "identifier": "iterm_mcp_server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -10577,7 +10577,7 @@ "registry_type": "oci", "identifier": "jmeter-mcp-server", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -10608,7 +10608,7 @@ "registry_type": "npm", "identifier": "@gongrzhe/server-json-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -10660,7 +10660,7 @@ "registry_type": "npm", "identifier": "jupiter-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -10691,7 +10691,7 @@ "registry_type": "pypi", "identifier": "lamaalrajih", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -10747,7 +10747,7 @@ "registry_type": "npm", "identifier": "keycloak-model-context-protocol", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -10836,7 +10836,7 @@ "registry_type": "oci", "identifier": "@kiwamizamurai/mcp-kibela-server", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -10877,7 +10877,7 @@ "registry_type": "oci", "identifier": "kong-konnect-mcp", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -10908,7 +10908,7 @@ "registry_type": "pypi", "identifier": "mcp-server-kubernetes", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -10945,7 +10945,7 @@ "registry_type": "oci", "identifier": "doc-qa-server", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -10976,7 +10976,7 @@ "registry_type": "oci", "identifier": "mcp-server-lark", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -11017,7 +11017,7 @@ "registry_type": "npm", "identifier": "lightdash-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -11060,7 +11060,7 @@ "registry_type": "oci", "identifier": "lsp-mcp-server", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -11097,7 +11097,7 @@ "registry_type": "npm", "identifier": "@tacticlaunch/mcp-linear", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -11134,7 +11134,7 @@ "registry_type": "npm", "identifier": "linear-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -11217,7 +11217,7 @@ "registry_type": "npm", "identifier": "@llamaindex/mcp-server-llamacloud", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -11260,7 +11260,7 @@ "registry_type": "pypi", "identifier": "llm-context", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -11291,7 +11291,7 @@ "registry_type": "pypi", "identifier": "mac-messages-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -11365,7 +11365,7 @@ "registry_type": "pypi", "identifier": "mcp-server-mariadb", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -11396,7 +11396,7 @@ "registry_type": "npm", "identifier": "@liuyoshio/mcp-compass", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -11427,7 +11427,7 @@ "registry_type": "npm", "identifier": "mcp-create", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -11458,7 +11458,7 @@ "registry_type": "npm", "identifier": "@anaisbetts/mcp-installer", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -11519,7 +11519,7 @@ "registry_type": "oci", "identifier": "strowk/mcp-k8s-go", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -11571,7 +11571,7 @@ "registry_type": "pypi", "identifier": "mcp-local-rag", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -11602,7 +11602,7 @@ "registry_type": "pypi", "identifier": "mcp-proxy", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -11639,12 +11639,12 @@ "registry_type": "npm", "identifier": "TBXark", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "remotes": [ { - "transport_type": "sse", + "type": "sse", "url": "https://mcp.amap.com/sse?key=" } ], @@ -11676,7 +11676,7 @@ "registry_type": "pypi", "identifier": "mcp-salesforce", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -11707,7 +11707,7 @@ "registry_type": "oci", "identifier": "mem0-mcp", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -11773,7 +11773,7 @@ "registry_type": "pypi", "identifier": "membase-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -11836,7 +11836,7 @@ "registry_type": "pypi", "identifier": "metatrader-mcp-server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -11877,7 +11877,7 @@ "registry_type": "pypi", "identifier": "mcp-metricool", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -11951,7 +11951,7 @@ "registry_type": "pypi", "identifier": "mssql_mcp_server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -11982,7 +11982,7 @@ "registry_type": "pypi", "identifier": "ocr", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -12019,7 +12019,7 @@ "registry_type": "npm", "identifier": "mcp-teams-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -12092,7 +12092,7 @@ "registry_type": "pypi", "identifier": "mcp-server-mikrotik", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -12144,7 +12144,7 @@ "registry_type": "oci", "identifier": "mindmap-mcp-server", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -12175,7 +12175,7 @@ "registry_type": "npm", "identifier": "@mobilenext/mobile-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -12217,7 +12217,7 @@ "registry_type": "npm", "identifier": "mcp-mongo-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -12248,7 +12248,7 @@ "registry_type": "npm", "identifier": "mongodb-lens", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -12279,7 +12279,7 @@ "registry_type": "pypi", "identifier": "mcp-server-monday", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -12310,7 +12310,7 @@ "registry_type": "pypi", "identifier": "multicluster-mcp-server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -12341,7 +12341,7 @@ "registry_type": "oci", "identifier": "multi-model-advisor", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -12405,7 +12405,7 @@ "registry_type": "npm", "identifier": "@benborla29/mcp-server-mysql", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -12479,7 +12479,7 @@ "registry_type": "pypi", "identifier": "mysql_mcp_server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -12531,7 +12531,7 @@ "registry_type": "npm", "identifier": "n8n-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -12624,7 +12624,7 @@ "registry_type": "npm", "identifier": "@programcomputer/nasa-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -12667,7 +12667,7 @@ "registry_type": "pypi", "identifier": "nasdaq-data-link-mcp-os", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -12704,7 +12704,7 @@ "registry_type": "npm", "identifier": "mcp-server-nationalparks", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -12735,7 +12735,7 @@ "registry_type": "pypi", "identifier": "mcp-naver", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -12766,7 +12766,7 @@ "registry_type": "oci", "identifier": "mcp-server-nba", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -12814,7 +12814,7 @@ "registry_type": "npm", "identifier": "ns-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -12859,7 +12859,7 @@ "registry_type": "npm", "identifier": "@alanse/mcp-neo4j-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -12900,7 +12900,7 @@ "registry_type": "npm", "identifier": "mcp-neovim-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -12980,7 +12980,7 @@ "registry_type": "oci", "identifier": "kocierik/mcp-nomad", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -13032,7 +13032,7 @@ "registry_type": "npm", "identifier": "@suekou/mcp-notion-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -13069,7 +13069,7 @@ "registry_type": "oci", "identifier": "notionmcp", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -13117,7 +13117,7 @@ "registry_type": "npm", "identifier": "ntfy-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -13154,7 +13154,7 @@ "registry_type": "npm", "identifier": "ntfy-me-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -13196,7 +13196,7 @@ "registry_type": "npm", "identifier": "mcp-obsidian", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -13247,7 +13247,7 @@ "registry_type": "pypi", "identifier": "obsidian-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -13310,7 +13310,7 @@ "registry_type": "pypi", "identifier": "oceanbase_mcp_server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -13362,7 +13362,7 @@ "registry_type": "pypi", "identifier": "office-powerpoint-mcp-server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -13403,7 +13403,7 @@ "registry_type": "pypi", "identifier": "office-word-mcp-server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -13444,7 +13444,7 @@ "registry_type": "oci", "identifier": "okta-mcp-server", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -13493,7 +13493,7 @@ "registry_type": "pypi", "identifier": "openai-websearch-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -13524,7 +13524,7 @@ "registry_type": "pypi", "identifier": "openapi-mcp-server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -13614,7 +13614,7 @@ "registry_type": "oci", "identifier": "mcp-server-any-openapi", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -13656,7 +13656,7 @@ "registry_type": "npm", "identifier": "mcp-openapi-schema", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -13708,7 +13708,7 @@ "registry_type": "oci", "identifier": "opencti-server", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -13769,7 +13769,7 @@ "registry_type": "oci", "identifier": "opendota-mcp-server", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -13800,7 +13800,7 @@ "registry_type": "npm", "identifier": "openrpc-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -13843,7 +13843,7 @@ "registry_type": "oci", "identifier": "osp-marketing-tools", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -13874,7 +13874,7 @@ "registry_type": "pypi", "identifier": "mcp-outline", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -13932,7 +13932,7 @@ "registry_type": "pypi", "identifier": "pancakeswap-poolspy-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -13963,7 +13963,7 @@ "registry_type": "pypi", "identifier": "mcp-pandoc", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -14035,7 +14035,7 @@ "registry_type": "oci", "identifier": "mcp-paradex", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -14066,7 +14066,7 @@ "registry_type": "oci", "identifier": "mcp-pif", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -14119,7 +14119,7 @@ "registry_type": "pypi", "identifier": "mcp-pinecone", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -14150,7 +14150,7 @@ "registry_type": "npm", "identifier": "@felores/placid-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -14181,7 +14181,7 @@ "registry_type": "oci", "identifier": "plane-mcp-server", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -14212,7 +14212,7 @@ "registry_type": "npm", "identifier": "@executeautomation/playwright-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -14243,7 +14243,7 @@ "registry_type": "npm", "identifier": "mcp-postman", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -14274,7 +14274,7 @@ "registry_type": "pypi", "identifier": "mcp-prefect", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -14311,7 +14311,7 @@ "registry_type": "npm", "identifier": "productboard-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -14408,7 +14408,7 @@ "registry_type": "oci", "identifier": "prometheus_mcp_server", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -14439,7 +14439,7 @@ "registry_type": "pypi", "identifier": "pubchem_mcp_server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -14527,7 +14527,7 @@ "registry_type": "oci", "identifier": "pulumi-mcp-server", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -14558,7 +14558,7 @@ "registry_type": "npm", "identifier": "puppeteer-vision-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -14620,7 +14620,7 @@ "registry_type": "npm", "identifier": "pushover-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -14672,7 +14672,7 @@ "registry_type": "pypi", "identifier": "qgis-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -14703,7 +14703,7 @@ "registry_type": "npm", "identifier": "@gongrzhe/quickchart-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -14740,7 +14740,7 @@ "registry_type": "oci", "identifier": "qwen_max", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -14842,7 +14842,7 @@ "registry_type": "pypi", "identifier": "mcp-server-rabbitmq", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -14873,7 +14873,7 @@ "registry_type": "npm", "identifier": "@apify/mcp-server-rag-web-browser", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -14921,7 +14921,7 @@ "registry_type": "oci", "identifier": "raindrop-io-mcp-server", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -14952,7 +14952,7 @@ "registry_type": "oci", "identifier": "reaper-mcp-server", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -15003,7 +15003,7 @@ "registry_type": "oci", "identifier": "@gongrzhe/server-redis-mcp", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -15034,7 +15034,7 @@ "registry_type": "pypi", "identifier": "mcp-server-redis", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -15071,7 +15071,7 @@ "registry_type": "pypi", "identifier": "mcp-server-rememberizer", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -15108,7 +15108,7 @@ "registry_type": "npm", "identifier": "mcp-replicate", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -15139,7 +15139,7 @@ "registry_type": "pypi", "identifier": "mcp-rquest", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -15176,7 +15176,7 @@ "registry_type": "npm", "identifier": "mcp-server-rijksmuseum", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -15207,7 +15207,7 @@ "registry_type": "pypi", "identifier": "riot", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -15238,7 +15238,7 @@ "registry_type": "pypi", "identifier": "mcp-salesforce-connector", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -15269,7 +15269,7 @@ "registry_type": "pypi", "identifier": "mcp-scholarly", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -15300,7 +15300,7 @@ "registry_type": "pypi", "identifier": "scrapling-fetch-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -15369,7 +15369,7 @@ "registry_type": "oci", "identifier": "mcp-searxng", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -15400,7 +15400,7 @@ "registry_type": "pypi", "identifier": "sec-edgar-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -15460,7 +15460,7 @@ "registry_type": "pypi", "identifier": "servicenow-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -15513,7 +15513,7 @@ "registry_type": "npm", "identifier": "shopify-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -15544,7 +15544,7 @@ "registry_type": "npm", "identifier": "mcp-server-siri-shortcuts", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -15606,7 +15606,7 @@ "registry_type": "pypi", "identifier": "mcp_snowflake_server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -15637,7 +15637,7 @@ "registry_type": "pypi", "identifier": "mcp-solver", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -15668,7 +15668,7 @@ "registry_type": "oci", "identifier": "mcp-soccer-data", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -15699,7 +15699,7 @@ "registry_type": "npm", "identifier": "solana-agent-kit", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -15765,7 +15765,7 @@ "registry_type": "pypi", "identifier": "spotify-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -15796,7 +15796,7 @@ "registry_type": "pypi", "identifier": "strava-mcp-server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -15839,7 +15839,7 @@ "registry_type": "oci", "identifier": "mcp-stripe", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -15906,7 +15906,7 @@ "registry_type": "pypi", "identifier": "wilsonchenghy", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -15937,7 +15937,7 @@ "registry_type": "npm", "identifier": "cursor-talk-to-figma-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -15974,7 +15974,7 @@ "registry_type": "oci", "identifier": "mcp-server-tmdb", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -16023,7 +16023,7 @@ "registry_type": "pypi", "identifier": "mcp_tavily", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -16054,7 +16054,7 @@ "registry_type": "oci", "identifier": "teradata-mcp", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -16097,7 +16097,7 @@ "registry_type": "pypi", "identifier": "terminal-controller", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -16160,7 +16160,7 @@ "registry_type": "npm", "identifier": "mcp-server-tft", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -16218,7 +16218,7 @@ "registry_type": "pypi", "identifier": "thegraph-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -16255,7 +16255,7 @@ "registry_type": "npm", "identifier": "@delorenj/mcp-server-ticketmaster", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -16361,7 +16361,7 @@ "registry_type": "oci", "identifier": "@alexarevalo.ai/mcp-server-ticktick", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -16398,7 +16398,7 @@ "registry_type": "npm", "identifier": "@abhiz123/todoist-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -16450,7 +16450,7 @@ "registry_type": "npm", "identifier": "token-minter-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -16491,7 +16491,7 @@ "registry_type": "npm", "identifier": "token-revoke-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -16564,7 +16564,7 @@ "registry_type": "npm", "identifier": "typesense-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -16601,7 +16601,7 @@ "registry_type": "npm", "identifier": "@gongrzhe/server-travelplanner-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -16648,7 +16648,7 @@ "registry_type": "pypi", "identifier": "uniswap-poolspy-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -16700,7 +16700,7 @@ "registry_type": "npm", "identifier": "uniswap-trader-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -16781,7 +16781,7 @@ "registry_type": "oci", "identifier": "mcp-server-unitycatalog", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -16812,7 +16812,7 @@ "registry_type": "oci", "identifier": "com.gamelovers.mcp-unity", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -16849,7 +16849,7 @@ "registry_type": "oci", "identifier": "com.quaza.unitymcp", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -16880,7 +16880,7 @@ "registry_type": "oci", "identifier": "mcp-server-vegalite", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -16947,7 +16947,7 @@ "registry_type": "pypi", "identifier": "video-editor-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -17028,7 +17028,7 @@ "registry_type": "pypi", "identifier": "videocapture-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -17077,7 +17077,7 @@ "registry_type": "npm", "identifier": "@mfukushim/map-traveler-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -17154,7 +17154,7 @@ "registry_type": "oci", "identifier": "mcp-server-tos", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -17191,7 +17191,7 @@ "registry_type": "npm", "identifier": "wanaku-ai", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -17239,7 +17239,7 @@ "registry_type": "npm", "identifier": "webflow-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -17276,7 +17276,7 @@ "registry_type": "npm", "identifier": "whale-tracker-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -17307,7 +17307,7 @@ "registry_type": "npm", "identifier": "@bharathvaj/whois-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -17338,7 +17338,7 @@ "registry_type": "oci", "identifier": "mcp-wikidata", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -17369,7 +17369,7 @@ "registry_type": "npm", "identifier": "@simonb97/server-win-cli", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -17421,7 +17421,7 @@ "registry_type": "pypi", "identifier": "world_bank_mcp_server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -17470,7 +17470,7 @@ "registry_type": "npm", "identifier": "@enescinar/twitter-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -17529,7 +17529,7 @@ "registry_type": "pypi", "identifier": "x-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -17560,7 +17560,7 @@ "registry_type": "pypi", "identifier": "mcpxcodebuild", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -17605,7 +17605,7 @@ "registry_type": "npm", "identifier": "xero-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -17636,12 +17636,12 @@ "registry_type": "pypi", "identifier": "xiyan_mcp_server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "remotes": [ { - "transport_type": "sse", + "type": "sse", "url": "http://localhost:8000/sse" } ], @@ -17684,7 +17684,7 @@ "registry_type": "npm", "identifier": "@41px/mcp-xmind", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -17715,7 +17715,7 @@ "registry_type": "oci", "identifier": "ynabmcpserver", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -17752,7 +17752,7 @@ "registry_type": "npm", "identifier": "zubeid-youtube-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -17797,7 +17797,7 @@ "registry_type": "npm", "identifier": "@prathamesh0901/zoom-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -17828,7 +17828,7 @@ "registry_type": "pypi", "identifier": "mcp_weather_server", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -17859,7 +17859,7 @@ "registry_type": "npm", "identifier": "easy-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -17890,7 +17890,7 @@ "registry_type": "pypi", "identifier": "fastapi-mcp", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -17938,7 +17938,7 @@ "registry_type": "npm", "identifier": "fastmcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -17986,12 +17986,12 @@ "registry_type": "npm", "identifier": "@mcpdotdirect/create-mcp-server", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "remotes": [ { - "transport_type": "sse", + "type": "sse", "url": "http://localhost:3001/sse" } ], @@ -18029,7 +18029,7 @@ "registry_type": "npm", "identifier": "@marimo-team/codemirror-mcp", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -18071,7 +18071,7 @@ "registry_type": "npm", "identifier": "jaw9c", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -18118,7 +18118,7 @@ "registry_type": "npm", "identifier": "my-docs-site", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -18149,7 +18149,7 @@ "registry_type": "npm", "identifier": "@wong2/mcp-cli", "registry_base_url": "https://registry.npmjs.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -18180,7 +18180,7 @@ "registry_type": "pypi", "identifier": "mcpm", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -18211,7 +18211,7 @@ "registry_type": "pypi", "identifier": "mcp-manager", "registry_base_url": "https://pypi.org", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -18242,7 +18242,7 @@ "registry_type": "oci", "identifier": "mcphub-desktop", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { @@ -18273,7 +18273,7 @@ "registry_type": "oci", "identifier": "navfast", "registry_base_url": "https://docker.io", - "transport_type": "stdio" + "transport": {"type": "stdio"} } ], "_meta": { diff --git a/docs/server-json/examples.md b/docs/server-json/examples.md index 8ef9ccb..5cba5cf 100644 --- a/docs/server-json/examples.md +++ b/docs/server-json/examples.md @@ -21,6 +21,9 @@ "registry_base_url": "https://registry.npmjs.org", "identifier": "@modelcontextprotocol/server-brave-search", "version": "1.0.2", + "transport": { + "type": "stdio" + }, "environment_variables": [ { "name": "BRAVE_API_KEY", @@ -60,6 +63,9 @@ Suppose your MCP server application requires a `mcp start` CLI arguments to star "registry_base_url": "https://api.nuget.org", "identifier": "Knapcode.SampleMcpServer", "version": "0.4.0-beta", + "transport": { + "type": "stdio" + }, "package_arguments": [ { "type": "positional", @@ -109,6 +115,9 @@ This will essentially instruct the MCP client to execute `dnx Knapcode.SampleMcp "registry_base_url": "https://registry.npmjs.org", "identifier": "@modelcontextprotocol/server-filesystem", "version": "1.0.2", + "transport": { + "type": "stdio" + }, "package_arguments": [ { "type": "positional", @@ -132,6 +141,9 @@ This will essentially instruct the MCP client to execute `dnx Knapcode.SampleMcp "registry_base_url": "https://docker.io", "identifier": "mcp/filesystem", "version": "1.0.2", + "transport": { + "type": "stdio" + }, "runtime_arguments": [ { "type": "named", @@ -201,7 +213,7 @@ This will essentially instruct the MCP client to execute `dnx Knapcode.SampleMcp }, "remotes": [ { - "transport_type": "sse", + "type": "sse", "url": "http://mcp-fs.anonymous.modelcontextprotocol.io/sse" } ], @@ -241,6 +253,9 @@ This will essentially instruct the MCP client to execute `dnx Knapcode.SampleMcp "identifier": "weather-mcp-server", "version": "0.5.0", "runtime_hint": "uvx", + "transport": { + "type": "stdio" + }, "environment_variables": [ { "name": "WEATHER_API_KEY", @@ -294,6 +309,9 @@ The `dnx` tool ships with the .NET 10 SDK, starting with Preview 6. "identifier": "Knapcode.SampleMcpServer", "version": "0.5.0", "runtime_hint": "dnx", + "transport": { + "type": "stdio" + }, "environment_variables": [ { "name": "WEATHER_CHOICES", @@ -340,6 +358,9 @@ The `dnx` tool ships with the .NET 10 SDK, starting with Preview 6. "registry_base_url": "https://docker.io", "identifier": "example/database-manager-mcp", "version": "3.1.0", + "transport": { + "type": "stdio" + }, "runtime_arguments": [ { "type": "named", @@ -451,6 +472,9 @@ The `dnx` tool ships with the .NET 10 SDK, starting with Preview 6. "identifier": "@example/hybrid-mcp-server", "version": "1.5.0", "runtime_hint": "npx", + "transport": { + "type": "stdio" + }, "package_arguments": [ { "type": "named", @@ -468,7 +492,7 @@ The `dnx` tool ships with the .NET 10 SDK, starting with Preview 6. ], "remotes": [ { - "transport_type": "sse", + "type": "sse", "url": "https://mcp.anonymous.modelcontextprotocol.io/sse", "headers": [ { @@ -490,7 +514,7 @@ The `dnx` tool ships with the .NET 10 SDK, starting with Preview 6. ] }, { - "transport_type": "streamable-http", + "type": "streamable-http", "url": "https://mcp.anonymous.modelcontextprotocol.io/http" } ], @@ -532,7 +556,10 @@ The `dnx` tool ships with the .NET 10 SDK, starting with Preview 6. "registry_base_url": "https://github.com", "identifier": "https://github.com/modelcontextprotocol/text-editor-mcpb/releases/download/v1.0.2/text-editor.mcpb", "version": "1.0.2", - "file_sha256": "fe333e598595000ae021bd27117db32ec69af6987f507ba7a63c90638ff633ce" + "file_sha256": "fe333e598595000ae021bd27117db32ec69af6987f507ba7a63c90638ff633ce", + "transport": { + "type": "stdio" + } } ], "_meta": { @@ -574,6 +601,9 @@ This example shows an MCPB (MCP Bundle) package that: "registry_base_url": "https://registry.npmjs.org", "identifier": "@legacy/old-weather-server", "version": "0.9.5", + "transport": { + "type": "stdio" + }, "environment_variables": [ { "name": "WEATHER_API_KEY", diff --git a/docs/server-json/server.schema.json b/docs/server-json/server.schema.json index 1c65aec..84195bc 100644 --- a/docs/server-json/server.schema.json +++ b/docs/server-json/server.schema.json @@ -114,18 +114,23 @@ "examples": [ "npx", "uvx", + "docker", "dnx" ] }, - "transport_type": { - "type": "string", - "enum": [ - "streamable-http", - "sse", - "stdio" + "transport": { + "anyOf": [ + { + "$ref": "#/$defs/StdioTransport" + }, + { + "$ref": "#/$defs/StreamableHttpTransport" + }, + { + "$ref": "#/$defs/SseTransport" + } ], - "description": "Transport protocol type for the package", - "example": "stdio" + "description": "Transport protocol configuration for the package" }, "runtime_arguments": { "type": "array", @@ -323,26 +328,70 @@ } ] }, - "Remote": { + "StdioTransport": { "type": "object", "required": [ - "transport_type", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "stdio" + ], + "description": "Transport type", + "example": "stdio" + } + } + }, + "StreamableHttpTransport": { + "type": "object", + "required": [ + "type", "url" ], "properties": { - "transport_type": { + "type": { + "type": "string", + "enum": [ + "streamable-http" + ], + "description": "Transport type", + "example": "streamable-http" + }, + "url": { + "type": "string", + "description": "URL template for the streamable-http transport. Variables in {curly_braces} reference argument value_hints, argument names, or environment variable names. After variable substitution, this should produce a valid URI.", + "example": "https://api.example.com/mcp" + }, + "headers": { + "type": "array", + "description": "HTTP headers to include", + "items": { + "$ref": "#/$defs/KeyValueInput" + } + } + } + }, + "SseTransport": { + "type": "object", + "required": [ + "type", + "url" + ], + "properties": { + "type": { "type": "string", "enum": [ - "streamable-http", "sse" ], - "description": "Transport protocol type", + "description": "Transport type", "example": "sse" }, "url": { "type": "string", "format": "uri", - "description": "Remote server URL", + "description": "Server-Sent Events endpoint URL", "example": "https://mcp-fs.example.com/sse" }, "headers": { @@ -378,7 +427,14 @@ "remotes": { "type": "array", "items": { - "$ref": "#/$defs/Remote" + "anyOf": [ + { + "$ref": "#/$defs/StreamableHttpTransport" + }, + { + "$ref": "#/$defs/SseTransport" + } + ] } }, "_meta": { diff --git a/internal/api/handlers/v0/publish_integration_test.go b/internal/api/handlers/v0/publish_integration_test.go index 7cd3a26..8b8ac37 100644 --- a/internal/api/handlers/v0/publish_integration_test.go +++ b/internal/api/handlers/v0/publish_integration_test.go @@ -234,6 +234,9 @@ func TestPublishIntegration(t *testing.T) { RegistryType: model.RegistryTypeMCPB, Identifier: "github.com/domdomegg/airtable-mcp-server/releases/download/v1.7.2/airtable-mcp-server.mcpb", Version: "1.7.2", + Transport: model.Transport{ + Type: model.TransportTypeStdio, + }, }, }, } diff --git a/internal/api/handlers/v0/publish_registry_validation_test.go b/internal/api/handlers/v0/publish_registry_validation_test.go index 81bffa1..b1091c9 100644 --- a/internal/api/handlers/v0/publish_registry_validation_test.go +++ b/internal/api/handlers/v0/publish_registry_validation_test.go @@ -55,6 +55,9 @@ func TestPublishRegistryValidation(t *testing.T) { RegistryType: model.RegistryTypeNPM, Identifier: "nonexistent-npm-package-xyz123", Version: "1.0.0", + Transport: model.Transport{ + Type: model.TransportTypeStdio, + }, }, }, } @@ -95,6 +98,9 @@ func TestPublishRegistryValidation(t *testing.T) { RegistryType: model.RegistryTypeMCPB, Identifier: "https://github.com/microsoft/playwright-mcp/releases/download/v0.0.36/playwright-mcp-extension-v0.0.36.zip", Version: "0.0.36", + Transport: model.Transport{ + Type: model.TransportTypeStdio, + }, }, }, } @@ -143,11 +149,17 @@ func TestPublishRegistryValidation(t *testing.T) { RegistryType: model.RegistryTypeMCPB, Identifier: "https://github.com/microsoft/playwright-mcp/releases/download/v0.0.36/playwright-mcp-extension-v0.0.36.zip", Version: "1.0.0", + Transport: model.Transport{ + Type: model.TransportTypeStdio, + }, }, { RegistryType: model.RegistryTypeNPM, Identifier: "nonexistent-second-package-abc123", Version: "1.0.0", + Transport: model.Transport{ + Type: model.TransportTypeStdio, + }, }, }, } @@ -189,11 +201,17 @@ func TestPublishRegistryValidation(t *testing.T) { RegistryType: model.RegistryTypeNPM, Identifier: "nonexistent-first-package-xyz789", Version: "1.0.0", + Transport: model.Transport{ + Type: model.TransportTypeStdio, + }, }, { RegistryType: model.RegistryTypeMCPB, Identifier: "https://github.com/microsoft/playwright-mcp/releases/download/v0.0.36/playwright-mcp-extension-v0.0.36.zip", Version: "1.0.0", + Transport: model.Transport{ + Type: model.TransportTypeStdio, + }, }, }, } diff --git a/internal/api/handlers/v0/publish_test.go b/internal/api/handlers/v0/publish_test.go index 456da18..81bf588 100644 --- a/internal/api/handlers/v0/publish_test.go +++ b/internal/api/handlers/v0/publish_test.go @@ -222,6 +222,9 @@ func TestPublishEndpoint(t *testing.T) { RegistryType: model.RegistryTypeMCPB, Identifier: "https://github.com/example/server/releases/download/v1.0.0/server.tar.gz", Version: "1.0.0", + Transport: model.Transport{ + Type: model.TransportTypeStdio, + }, }, }, }, diff --git a/internal/service/registry_service_test.go b/internal/service/registry_service_test.go index 5ecaa40..4b4df7a 100644 --- a/internal/service/registry_service_test.go +++ b/internal/service/registry_service_test.go @@ -21,9 +21,9 @@ func TestValidateNoDuplicateRemoteURLs(t *testing.T) { VersionDetail: model.VersionDetail{ Version: "1.0.0", }, - Remotes: []model.Remote{ - {URL: "https://api.example.com/mcp"}, - {URL: "https://webhook.example.com/sse"}, + Remotes: []model.Transport{ + {Type: "streamable-http", URL: "https://api.example.com/mcp"}, + {Type: "sse", URL: "https://webhook.example.com/sse"}, }, }, "existing2": { @@ -32,8 +32,8 @@ func TestValidateNoDuplicateRemoteURLs(t *testing.T) { VersionDetail: model.VersionDetail{ Version: "1.0.0", }, - Remotes: []model.Remote{ - {URL: "https://api.microsoft.com/mcp"}, + Remotes: []model.Transport{ + {Type: "streamable-http", URL: "https://api.microsoft.com/mcp"}, }, }, } @@ -62,7 +62,7 @@ func TestValidateNoDuplicateRemoteURLs(t *testing.T) { VersionDetail: model.VersionDetail{ Version: "1.0.0", }, - Remotes: []model.Remote{}, + Remotes: []model.Transport{}, }, expectError: false, }, @@ -74,9 +74,9 @@ func TestValidateNoDuplicateRemoteURLs(t *testing.T) { VersionDetail: model.VersionDetail{ Version: "1.0.0", }, - Remotes: []model.Remote{ - {URL: "https://new.example.com/mcp"}, - {URL: "https://unique.example.com/sse"}, + Remotes: []model.Transport{ + {Type: "streamable-http", URL: "https://new.example.com/mcp"}, + {Type: "sse", URL: "https://unique.example.com/sse"}, }, }, expectError: false, @@ -89,8 +89,8 @@ func TestValidateNoDuplicateRemoteURLs(t *testing.T) { VersionDetail: model.VersionDetail{ Version: "1.0.0", }, - Remotes: []model.Remote{ - {URL: "https://api.example.com/mcp"}, // This URL already exists + Remotes: []model.Transport{ + {Type: "streamable-http", URL: "https://api.example.com/mcp"}, // This URL already exists }, }, expectError: true, @@ -104,8 +104,8 @@ func TestValidateNoDuplicateRemoteURLs(t *testing.T) { VersionDetail: model.VersionDetail{ Version: "1.1.0", }, - Remotes: []model.Remote{ - {URL: "https://api.example.com/mcp"}, // Same URL as before + Remotes: []model.Transport{ + {Type: "streamable-http", URL: "https://api.example.com/mcp"}, // Same URL as before }, }, expectError: false, diff --git a/internal/validators/utils.go b/internal/validators/utils.go index 512020b..61b122f 100644 --- a/internal/validators/utils.go +++ b/internal/validators/utils.go @@ -30,10 +30,51 @@ func HasNoSpaces(s string) bool { return !strings.Contains(s, " ") } -// IsValidURL checks if a URL is in valid format +// extractTemplateVariables extracts template variables from a URL string +// e.g., "http://{host}:{port}/mcp" returns ["host", "port"] +func extractTemplateVariables(url string) []string { + re := regexp.MustCompile(`\{([^}]+)\}`) + matches := re.FindAllStringSubmatch(url, -1) + + var variables []string + for _, match := range matches { + if len(match) > 1 { + variables = append(variables, match[1]) + } + } + return variables +} + +// replaceTemplateVariables replaces template variables with placeholder values for URL validation +func replaceTemplateVariables(rawURL string) string { + // Replace common template variables with valid placeholder values for parsing + templateReplacements := map[string]string{ + "{host}": "example.com", + "{port}": "8080", + "{path}": "api", + "{protocol}": "http", + "{scheme}": "http", + } + + result := rawURL + for placeholder, replacement := range templateReplacements { + result = strings.ReplaceAll(result, placeholder, replacement) + } + + // Handle any remaining {variable} patterns with generic placeholder + re := regexp.MustCompile(`\{[^}]+\}`) + result = re.ReplaceAllString(result, "placeholder") + + return result +} + +// IsValidURL checks if a URL is in valid format (basic structure validation) func IsValidURL(rawURL string) bool { + // Replace template variables with placeholders for parsing + testURL := replaceTemplateVariables(rawURL) + // Parse the URL - u, err := url.Parse(rawURL) + u, err := url.Parse(testURL) if err != nil { return false } @@ -43,8 +84,67 @@ func IsValidURL(rawURL string) bool { return false } - if u.Host == "" || u.Hostname() == "localhost" { + if u.Host == "" { return false } return true } + +// IsValidRemoteURL checks if a URL is valid for remotes (stricter than packages - no localhost allowed) +func IsValidRemoteURL(rawURL string) bool { + // First check basic URL structure + if !IsValidURL(rawURL) { + return false + } + + // Parse the URL to check for localhost restriction + u, err := url.Parse(rawURL) + if err != nil { + return false + } + + // Reject localhost URLs for remotes (security/production concerns) + hostname := u.Hostname() + if hostname == "localhost" || hostname == "127.0.0.1" || strings.HasSuffix(hostname, ".localhost") { + return false + } + + return true +} + +// IsValidTemplatedURL validates a URL with template variables against available variables +// For packages: validates that template variables reference package arguments or environment variables +// For remotes: disallows template variables entirely +func IsValidTemplatedURL(rawURL string, availableVariables []string, allowTemplates bool) bool { + // First check basic URL structure + if !IsValidURL(rawURL) { + return false + } + + // Extract template variables from URL + templateVars := extractTemplateVariables(rawURL) + + // If no templates are found, it's a valid static URL + if len(templateVars) == 0 { + return true + } + + // If templates are not allowed (e.g., for remotes), reject URLs with templates + if !allowTemplates { + return false + } + + // Validate that all template variables are available + availableSet := make(map[string]bool) + for _, v := range availableVariables { + availableSet[v] = true + } + + for _, templateVar := range templateVars { + if !availableSet[templateVar] { + return false + } + } + + return true +} diff --git a/internal/validators/validators.go b/internal/validators/validators.go index 756f530..d6c2a6a 100644 --- a/internal/validators/validators.go +++ b/internal/validators/validators.go @@ -34,7 +34,7 @@ func ValidateServerJSON(serverJSON *apiv0.ServerJSON) error { // Validate all remotes for _, remote := range serverJSON.Remotes { - if err := validateRemote(&remote); err != nil { + if err := validateTransport(&remote); err != nil { return err } } @@ -81,6 +81,12 @@ func validatePackageField(obj *model.Package) error { } } + // Validate transport with template variable support + availableVariables := collectAvailableVariables(obj) + if err := validatePackageTransport(&obj.Transport, availableVariables); err != nil { + return fmt.Errorf("invalid transport: %w", err) + } + return nil } @@ -130,11 +136,83 @@ func validateArgumentValueFields(name, value, defaultValue string) error { return nil } -func validateRemote(obj *model.Remote) error { - if !IsValidURL(obj.URL) { - return fmt.Errorf("%w: %s", ErrInvalidRemoteURL, obj.URL) +// collectAvailableVariables collects all available template variables from a package +func collectAvailableVariables(pkg *model.Package) []string { + var variables []string + + // Add environment variable names + for _, env := range pkg.EnvironmentVariables { + variables = append(variables, env.Name) + } + + // Add runtime argument names and value hints + for _, arg := range pkg.RuntimeArguments { + if arg.Name != "" { + variables = append(variables, arg.Name) + } + if arg.ValueHint != "" { + variables = append(variables, arg.ValueHint) + } + } + + // Add package argument names and value hints + for _, arg := range pkg.PackageArguments { + if arg.Name != "" { + variables = append(variables, arg.Name) + } + if arg.ValueHint != "" { + variables = append(variables, arg.ValueHint) + } + } + + return variables +} + +// validatePackageTransport validates a package's transport with templating support +func validatePackageTransport(transport *model.Transport, availableVariables []string) error { + // Validate transport type is supported + switch transport.Type { + case model.TransportTypeStdio: + // No additional validation needed for stdio - URL should be empty + return nil + case model.TransportTypeStreamableHTTP, model.TransportTypeSSE: + // URL is required for streamable-http and sse + if transport.URL == "" { + return fmt.Errorf("url is required for %s transport type", transport.Type) + } + // Validate URL format with template variable support + if !IsValidTemplatedURL(transport.URL, availableVariables, true) { + // Check if it's a template variable issue or basic URL issue + templateVars := extractTemplateVariables(transport.URL) + if len(templateVars) > 0 { + return fmt.Errorf("%w: template variables in URL %s reference undefined variables. Available variables: %v", + ErrInvalidRemoteURL, transport.URL, availableVariables) + } + return fmt.Errorf("%w: %s", ErrInvalidRemoteURL, transport.URL) + } + return nil + default: + return fmt.Errorf("unsupported transport type: %s", transport.Type) + } +} + +// validateTransport validates a remote transport (no templating allowed) +func validateTransport(obj *model.Transport) error { + // Validate transport type is supported - remotes only support streamable-http and sse + switch obj.Type { + case model.TransportTypeStreamableHTTP, model.TransportTypeSSE: + // URL is required for streamable-http and sse + if obj.URL == "" { + return fmt.Errorf("url is required for %s transport type", obj.Type) + } + // Validate URL format (no templates allowed for remotes, no localhost) + if !IsValidRemoteURL(obj.URL) { + return fmt.Errorf("%w: %s", ErrInvalidRemoteURL, obj.URL) + } + return nil + default: + return fmt.Errorf("unsupported transport type for remotes: %s (only streamable-http and sse are supported)", obj.Type) } - return nil } // ValidatePublishRequest validates a complete publish request including extensions diff --git a/internal/validators/validators_test.go b/internal/validators/validators_test.go index 577a336..e9c71bf 100644 --- a/internal/validators/validators_test.go +++ b/internal/validators/validators_test.go @@ -35,11 +35,15 @@ func TestValidate(t *testing.T) { Identifier: "test-package", RegistryType: "npm", RegistryBaseURL: "https://registry.npmjs.org", + Transport: model.Transport{ + Type: "stdio", + }, }, }, - Remotes: []model.Remote{ + Remotes: []model.Transport{ { - URL: "https://example.com/remote", + Type: "streamable-http", + URL: "https://example.com/remote", }, }, }, @@ -107,6 +111,9 @@ func TestValidate(t *testing.T) { Identifier: "test package with spaces", RegistryType: "npm", RegistryBaseURL: "https://registry.npmjs.org", + Transport: model.Transport{ + Type: "stdio", + }, }, }, }, @@ -129,11 +136,17 @@ func TestValidate(t *testing.T) { Identifier: "valid-package", RegistryType: "npm", RegistryBaseURL: "https://registry.npmjs.org", + Transport: model.Transport{ + Type: "stdio", + }, }, { Identifier: "invalid package", // Has space RegistryType: "pypi", RegistryBaseURL: "https://pypi.org", + Transport: model.Transport{ + Type: "stdio", + }, }, }, }, @@ -151,9 +164,10 @@ func TestValidate(t *testing.T) { VersionDetail: model.VersionDetail{ Version: "1.0.0", }, - Remotes: []model.Remote{ + Remotes: []model.Transport{ { - URL: "not-a-valid-url", + Type: "streamable-http", + URL: "not-a-valid-url", }, }, }, @@ -171,9 +185,10 @@ func TestValidate(t *testing.T) { VersionDetail: model.VersionDetail{ Version: "1.0.0", }, - Remotes: []model.Remote{ + Remotes: []model.Transport{ { - URL: "example.com/remote", + Type: "streamable-http", + URL: "example.com/remote", }, }, }, @@ -191,9 +206,10 @@ func TestValidate(t *testing.T) { VersionDetail: model.VersionDetail{ Version: "1.0.0", }, - Remotes: []model.Remote{ + Remotes: []model.Transport{ { - URL: "http://localhost", + Type: "streamable-http", + URL: "http://localhost", }, }, }, @@ -211,9 +227,10 @@ func TestValidate(t *testing.T) { VersionDetail: model.VersionDetail{ Version: "1.0.0", }, - Remotes: []model.Remote{ + Remotes: []model.Transport{ { - URL: "http://localhost:3000", + Type: "streamable-http", + URL: "http://localhost:3000", }, }, }, @@ -231,12 +248,14 @@ func TestValidate(t *testing.T) { VersionDetail: model.VersionDetail{ Version: "1.0.0", }, - Remotes: []model.Remote{ + Remotes: []model.Transport{ { - URL: "https://valid.com/remote", + Type: "streamable-http", + URL: "https://valid.com/remote", }, { - URL: "invalid-url", + Type: "streamable-http", + URL: "invalid-url", }, }, }, @@ -272,7 +291,7 @@ func TestValidate(t *testing.T) { Version: "1.0.0", }, Packages: []model.Package{}, - Remotes: []model.Remote{}, + Remotes: []model.Transport{}, }, expectedError: "", }, @@ -303,8 +322,11 @@ func TestValidate_RemoteNamespaceMatch(t *testing.T) { name: "valid match - example.com domain", serverDetail: apiv0.ServerJSON{ Name: "com.example/test-server", - Remotes: []model.Remote{ - {URL: "https://example.com/mcp"}, + Remotes: []model.Transport{ + { + Type: "streamable-http", + URL: "https://example.com/mcp", + }, }, }, expectError: false, @@ -313,8 +335,11 @@ func TestValidate_RemoteNamespaceMatch(t *testing.T) { name: "valid match - subdomain mcp.example.com", serverDetail: apiv0.ServerJSON{ Name: "com.example/test-server", - Remotes: []model.Remote{ - {URL: "https://mcp.example.com/endpoint"}, + Remotes: []model.Transport{ + { + Type: "streamable-http", + URL: "https://mcp.example.com/endpoint", + }, }, }, expectError: false, @@ -323,8 +348,11 @@ func TestValidate_RemoteNamespaceMatch(t *testing.T) { name: "valid match - api subdomain", serverDetail: apiv0.ServerJSON{ Name: "com.example/api-server", - Remotes: []model.Remote{ - {URL: "https://api.example.com/mcp"}, + Remotes: []model.Transport{ + { + Type: "streamable-http", + URL: "https://api.example.com/mcp", + }, }, }, expectError: false, @@ -333,8 +361,11 @@ func TestValidate_RemoteNamespaceMatch(t *testing.T) { name: "invalid - wrong domain", serverDetail: apiv0.ServerJSON{ Name: "com.example/test-server", - Remotes: []model.Remote{ - {URL: "https://google.com/mcp"}, + Remotes: []model.Transport{ + { + Type: "streamable-http", + URL: "https://google.com/mcp", + }, }, }, expectError: true, @@ -344,8 +375,11 @@ func TestValidate_RemoteNamespaceMatch(t *testing.T) { name: "invalid - different domain entirely", serverDetail: apiv0.ServerJSON{ Name: "com.microsoft/server", - Remotes: []model.Remote{ - {URL: "https://api.github.com/endpoint"}, + Remotes: []model.Transport{ + { + Type: "streamable-http", + URL: "https://api.github.com/endpoint", + }, }, }, expectError: true, @@ -355,8 +389,11 @@ func TestValidate_RemoteNamespaceMatch(t *testing.T) { name: "invalid URL format", serverDetail: apiv0.ServerJSON{ Name: "com.example/test", - Remotes: []model.Remote{ - {URL: "not-a-valid-url"}, + Remotes: []model.Transport{ + { + Type: "streamable-http", + URL: "not-a-valid-url", + }, }, }, expectError: true, @@ -366,7 +403,7 @@ func TestValidate_RemoteNamespaceMatch(t *testing.T) { name: "empty remotes array", serverDetail: apiv0.ServerJSON{ Name: "com.example/test", - Remotes: []model.Remote{}, + Remotes: []model.Transport{}, }, expectError: false, }, @@ -374,9 +411,15 @@ func TestValidate_RemoteNamespaceMatch(t *testing.T) { name: "multiple valid remotes - different subdomains", serverDetail: apiv0.ServerJSON{ Name: "com.example/server", - Remotes: []model.Remote{ - {URL: "https://api.example.com/sse"}, - {URL: "https://mcp.example.com/websocket"}, + Remotes: []model.Transport{ + { + Type: "streamable-http", + URL: "https://api.example.com/sse", + }, + { + Type: "streamable-http", + URL: "https://mcp.example.com/websocket", + }, }, }, expectError: false, @@ -385,9 +428,15 @@ func TestValidate_RemoteNamespaceMatch(t *testing.T) { name: "one valid, one invalid remote", serverDetail: apiv0.ServerJSON{ Name: "com.example/server", - Remotes: []model.Remote{ - {URL: "https://example.com/sse"}, - {URL: "https://google.com/websocket"}, + Remotes: []model.Transport{ + { + Type: "streamable-http", + URL: "https://example.com/sse", + }, + { + Type: "streamable-http", + URL: "https://google.com/websocket", + }, }, }, expectError: true, @@ -679,6 +728,363 @@ func TestValidateArgument_ValidValueFields(t *testing.T) { } // Helper function to create a valid server with a specific argument for testing +func TestValidate_TransportValidation(t *testing.T) { + tests := []struct { + name string + serverDetail apiv0.ServerJSON + expectedError string + }{ + // Package transport tests - stdio (no URL required) + { + name: "package transport stdio without URL", + serverDetail: apiv0.ServerJSON{ + Name: "com.example/test-server", + Description: "A test server", + VersionDetail: model.VersionDetail{ + Version: "1.0.0", + }, + Packages: []model.Package{ + { + Identifier: "test-package", + RegistryType: "npm", + Transport: model.Transport{ + Type: "stdio", + }, + }, + }, + }, + expectedError: "", + }, + { + name: "package transport stdio with URL (should still work)", + serverDetail: apiv0.ServerJSON{ + Name: "com.example/test-server", + Description: "A test server", + VersionDetail: model.VersionDetail{ + Version: "1.0.0", + }, + Packages: []model.Package{ + { + Identifier: "test-package", + RegistryType: "npm", + Transport: model.Transport{ + Type: "stdio", + URL: "ignored-for-stdio", + }, + }, + }, + }, + expectedError: "", + }, + // Package transport tests - streamable-http (URL required) + { + name: "package transport streamable-http with valid URL", + serverDetail: apiv0.ServerJSON{ + Name: "com.example/test-server", + Description: "A test server", + VersionDetail: model.VersionDetail{ + Version: "1.0.0", + }, + Packages: []model.Package{ + { + Identifier: "test-package", + RegistryType: "npm", + Transport: model.Transport{ + Type: "streamable-http", + URL: "https://example.com/mcp", + }, + }, + }, + }, + expectedError: "", + }, + { + name: "package transport streamable-http with templated URL", + serverDetail: apiv0.ServerJSON{ + Name: "com.example/test-server", + Description: "A test server", + VersionDetail: model.VersionDetail{ + Version: "1.0.0", + }, + Packages: []model.Package{ + { + Identifier: "test-package", + RegistryType: "npm", + Transport: model.Transport{ + Type: "streamable-http", + URL: "http://{host}:{port}/mcp", + }, + EnvironmentVariables: []model.KeyValueInput{ + {Name: "host"}, + {Name: "port"}, + }, + }, + }, + }, + expectedError: "", + }, + { + name: "package transport streamable-http without URL", + serverDetail: apiv0.ServerJSON{ + Name: "com.example/test-server", + Description: "A test server", + VersionDetail: model.VersionDetail{ + Version: "1.0.0", + }, + Packages: []model.Package{ + { + Identifier: "test-package", + RegistryType: "npm", + Transport: model.Transport{ + Type: "streamable-http", + }, + }, + }, + }, + expectedError: "url is required for streamable-http transport type", + }, + { + name: "package transport streamable-http with templated URL missing variables", + serverDetail: apiv0.ServerJSON{ + Name: "com.example/test-server", + Description: "A test server", + VersionDetail: model.VersionDetail{ + Version: "1.0.0", + }, + Packages: []model.Package{ + { + Identifier: "test-package", + RegistryType: "npm", + Transport: model.Transport{ + Type: "streamable-http", + URL: "http://{host}:{port}/mcp", + }, + // Missing host and port variables + }, + }, + }, + expectedError: "template variables in URL", + }, + // Package transport tests - sse (URL required) + { + name: "package transport sse with valid URL", + serverDetail: apiv0.ServerJSON{ + Name: "com.example/test-server", + Description: "A test server", + VersionDetail: model.VersionDetail{ + Version: "1.0.0", + }, + Packages: []model.Package{ + { + Identifier: "test-package", + RegistryType: "npm", + Transport: model.Transport{ + Type: "sse", + URL: "https://example.com/events", + }, + }, + }, + }, + expectedError: "", + }, + { + name: "package transport sse without URL", + serverDetail: apiv0.ServerJSON{ + Name: "com.example/test-server", + Description: "A test server", + VersionDetail: model.VersionDetail{ + Version: "1.0.0", + }, + Packages: []model.Package{ + { + Identifier: "test-package", + RegistryType: "npm", + Transport: model.Transport{ + Type: "sse", + }, + }, + }, + }, + expectedError: "url is required for sse transport type", + }, + // Package transport tests - unsupported type + { + name: "package transport unsupported type", + serverDetail: apiv0.ServerJSON{ + Name: "com.example/test-server", + Description: "A test server", + VersionDetail: model.VersionDetail{ + Version: "1.0.0", + }, + Packages: []model.Package{ + { + Identifier: "test-package", + RegistryType: "npm", + Transport: model.Transport{ + Type: "websocket", + }, + }, + }, + }, + expectedError: "unsupported transport type: websocket", + }, + // Remote transport tests - streamable-http + { + name: "remote transport streamable-http with valid URL", + serverDetail: apiv0.ServerJSON{ + Name: "com.example/test-server", + Description: "A test server", + VersionDetail: model.VersionDetail{ + Version: "1.0.0", + }, + Remotes: []model.Transport{ + { + Type: "streamable-http", + URL: "https://example.com/mcp", + }, + }, + }, + expectedError: "", + }, + { + name: "remote transport streamable-http without URL", + serverDetail: apiv0.ServerJSON{ + Name: "com.example/test-server", + Description: "A test server", + VersionDetail: model.VersionDetail{ + Version: "1.0.0", + }, + Remotes: []model.Transport{ + { + Type: "streamable-http", + }, + }, + }, + expectedError: "url is required for streamable-http transport type", + }, + // Remote transport tests - sse + { + name: "remote transport sse with valid URL", + serverDetail: apiv0.ServerJSON{ + Name: "com.example/test-server", + Description: "A test server", + VersionDetail: model.VersionDetail{ + Version: "1.0.0", + }, + Remotes: []model.Transport{ + { + Type: "sse", + URL: "https://example.com/events", + }, + }, + }, + expectedError: "", + }, + { + name: "remote transport sse without URL", + serverDetail: apiv0.ServerJSON{ + Name: "com.example/test-server", + Description: "A test server", + VersionDetail: model.VersionDetail{ + Version: "1.0.0", + }, + Remotes: []model.Transport{ + { + Type: "sse", + }, + }, + }, + expectedError: "url is required for sse transport type", + }, + // Remote transport tests - unsupported types + { + name: "remote transport stdio not supported", + serverDetail: apiv0.ServerJSON{ + Name: "com.example/test-server", + Description: "A test server", + VersionDetail: model.VersionDetail{ + Version: "1.0.0", + }, + Remotes: []model.Transport{ + { + Type: "stdio", + }, + }, + }, + expectedError: "unsupported transport type for remotes: stdio", + }, + { + name: "remote transport unsupported type", + serverDetail: apiv0.ServerJSON{ + Name: "com.example/test-server", + Description: "A test server", + VersionDetail: model.VersionDetail{ + Version: "1.0.0", + }, + Remotes: []model.Transport{ + { + Type: "websocket", + URL: "wss://example.com/ws", + }, + }, + }, + expectedError: "unsupported transport type for remotes: websocket", + }, + // Localhost URL tests - packages vs remotes + { + name: "package transport allows localhost URLs", + serverDetail: apiv0.ServerJSON{ + Name: "com.example/test-server", + Description: "A test server", + VersionDetail: model.VersionDetail{ + Version: "1.0.0", + }, + Packages: []model.Package{ + { + Identifier: "test-package", + RegistryType: "npm", + Transport: model.Transport{ + Type: "streamable-http", + URL: "http://localhost:3000/mcp", + }, + }, + }, + }, + expectedError: "", + }, + { + name: "remote transport rejects localhost URLs", + serverDetail: apiv0.ServerJSON{ + Name: "com.example/test-server", + Description: "A test server", + VersionDetail: model.VersionDetail{ + Version: "1.0.0", + }, + Remotes: []model.Transport{ + { + Type: "streamable-http", + URL: "http://localhost:3000/mcp", + }, + }, + }, + expectedError: "invalid remote URL", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := validators.ValidateServerJSON(&tt.serverDetail) + + if tt.expectedError == "" { + assert.NoError(t, err) + } else { + assert.Error(t, err) + assert.Contains(t, err.Error(), tt.expectedError) + } + }) + } +} + func TestValidate_RegistryTypesAndUrls(t *testing.T) { testCases := []struct { tcName string @@ -735,6 +1141,9 @@ func TestValidate_RegistryTypesAndUrls(t *testing.T) { RegistryType: tc.registryType, RegistryBaseURL: tc.baseURL, Version: tc.version, + Transport: model.Transport{ + Type: "stdio", + }, }, }, } @@ -768,12 +1177,16 @@ func createValidServerWithArgument(arg model.Argument) apiv0.ServerJSON { Identifier: "test-package", RegistryType: "npm", RegistryBaseURL: "https://registry.npmjs.org", + Transport: model.Transport{ + Type: "stdio", + }, RuntimeArguments: []model.Argument{arg}, }, }, - Remotes: []model.Remote{ + Remotes: []model.Transport{ { - URL: "https://example.com/remote", + Type: "streamable-http", + URL: "https://example.com/remote", }, }, } diff --git a/pkg/api/v0/types.go b/pkg/api/v0/types.go index 85e2454..cbee39a 100644 --- a/pkg/api/v0/types.go +++ b/pkg/api/v0/types.go @@ -36,7 +36,7 @@ type ServerJSON struct { Repository model.Repository `json:"repository,omitempty"` VersionDetail model.VersionDetail `json:"version_detail"` Packages []model.Package `json:"packages,omitempty"` - Remotes []model.Remote `json:"remotes,omitempty"` + Remotes []model.Transport `json:"remotes,omitempty"` Meta *ServerMeta `json:"_meta,omitempty"` } diff --git a/pkg/model/types.go b/pkg/model/types.go index 50ae9d6..b396ba8 100644 --- a/pkg/model/types.go +++ b/pkg/model/types.go @@ -9,6 +9,13 @@ const ( StatusDeleted Status = "deleted" ) +// Transport represents transport configuration with optional URL templating +type Transport struct { + Type string `json:"type"` + URL string `json:"url,omitempty"` + Headers []KeyValueInput `json:"headers,omitempty"` +} + // Package represents a package configuration type Package struct { // RegistryType indicates how to download packages (e.g., "npm", "pypi", "oci", "mcpb") @@ -20,19 +27,12 @@ type Package struct { Version string `json:"version" minLength:"1"` FileSHA256 string `json:"file_sha256,omitempty"` RunTimeHint string `json:"runtime_hint,omitempty"` - TransportType string `json:"transport_type,omitempty"` + Transport Transport `json:"transport,omitempty"` RuntimeArguments []Argument `json:"runtime_arguments,omitempty"` PackageArguments []Argument `json:"package_arguments,omitempty"` EnvironmentVariables []KeyValueInput `json:"environment_variables,omitempty"` } -// Remote represents a remote connection endpoint -type Remote struct { - TransportType string `json:"transport_type"` - URL string `json:"url" format:"uri"` - Headers []KeyValueInput `json:"headers,omitempty"` -} - // Repository represents a source code repository as defined in the spec type Repository struct { URL string `json:"url"`