Просмотр исходного кода

Move marketplace types to @roo-code/types (#4671)

And do some cleanup & consolidation.
John Richmond 6 месяцев назад
Родитель
Сommit
7dd56d6551
24 измененных файлов с 147 добавлено и 237 удалено
  1. 1 0
      packages/types/src/index.ts
  2. 88 0
      packages/types/src/marketplace.ts
  3. 1 1
      src/services/marketplace/MarketplaceManager.ts
  4. 6 6
      src/services/marketplace/RemoteConfigLoader.ts
  5. 7 5
      src/services/marketplace/SimpleInstaller.ts
  6. 4 1
      src/services/marketplace/__tests__/MarketplaceManager.test.ts
  7. 1 1
      src/services/marketplace/__tests__/RemoteConfigLoader.test.ts
  8. 2 1
      src/services/marketplace/__tests__/SimpleInstaller.test.ts
  9. 1 0
      src/services/marketplace/__tests__/marketplace-setting-check.test.ts
  10. 7 7
      src/services/marketplace/__tests__/nested-parameters.spec.ts
  11. 2 21
      src/services/marketplace/__tests__/optional-parameters.spec.ts
  12. 1 2
      src/services/marketplace/index.ts
  13. 0 84
      src/services/marketplace/schemas.ts
  14. 0 92
      src/services/marketplace/types.ts
  15. 1 1
      src/shared/ExtensionMessage.ts
  16. 9 4
      src/shared/WebviewMessage.ts
  17. 1 1
      webview-ui/src/components/marketplace/MarketplaceViewStateManager.ts
  18. 3 3
      webview-ui/src/components/marketplace/components/MarketplaceInstallModal.tsx
  19. 2 2
      webview-ui/src/components/marketplace/components/MarketplaceItemCard.tsx
  20. 2 1
      webview-ui/src/components/marketplace/components/__tests__/MarketplaceInstallModal-optional-params.test.tsx
  21. 2 1
      webview-ui/src/components/marketplace/components/__tests__/MarketplaceInstallModal.test.tsx
  22. 1 1
      webview-ui/src/components/marketplace/components/__tests__/MarketplaceItemCard.test.tsx
  23. 4 1
      webview-ui/src/components/marketplace/utils/__tests__/grouping.test.ts
  24. 1 1
      webview-ui/src/components/marketplace/utils/grouping.ts

+ 1 - 0
packages/types/src/index.ts

@@ -7,6 +7,7 @@ export * from "./experiment.js"
 export * from "./global-settings.js"
 export * from "./history.js"
 export * from "./ipc.js"
+export * from "./marketplace.js"
 export * from "./mcp.js"
 export * from "./message.js"
 export * from "./mode.js"

+ 88 - 0
packages/types/src/marketplace.ts

@@ -0,0 +1,88 @@
+import { z } from "zod"
+
+/**
+ * Schema for MCP parameter definitions
+ */
+export const mcpParameterSchema = z.object({
+	name: z.string().min(1),
+	key: z.string().min(1),
+	placeholder: z.string().optional(),
+	optional: z.boolean().optional().default(false),
+})
+
+export type McpParameter = z.infer<typeof mcpParameterSchema>
+
+/**
+ * Schema for MCP installation method with name
+ */
+export const mcpInstallationMethodSchema = z.object({
+	name: z.string().min(1),
+	content: z.string().min(1),
+	parameters: z.array(mcpParameterSchema).optional(),
+	prerequisites: z.array(z.string()).optional(),
+})
+
+export type McpInstallationMethod = z.infer<typeof mcpInstallationMethodSchema>
+
+/**
+ * Component type validation
+ */
+export const marketplaceItemTypeSchema = z.enum(["mode", "mcp"] as const)
+
+export type MarketplaceItemType = z.infer<typeof marketplaceItemTypeSchema>
+
+/**
+ * Base schema for common marketplace item fields
+ */
+const baseMarketplaceItemSchema = z.object({
+	id: z.string().min(1),
+	name: z.string().min(1, "Name is required"),
+	description: z.string(),
+	author: z.string().optional(),
+	authorUrl: z.string().url("Author URL must be a valid URL").optional(),
+	tags: z.array(z.string()).optional(),
+	prerequisites: z.array(z.string()).optional(),
+})
+
+/**
+ * Type-specific schemas for YAML parsing (without type field, added programmatically)
+ */
+export const modeMarketplaceItemSchema = baseMarketplaceItemSchema.extend({
+	content: z.string().min(1), // YAML content for modes
+})
+
+export type ModeMarketplaceItem = z.infer<typeof modeMarketplaceItemSchema>
+
+export const mcpMarketplaceItemSchema = baseMarketplaceItemSchema.extend({
+	url: z.string().url(), // Required url field
+	content: z.union([z.string().min(1), z.array(mcpInstallationMethodSchema)]), // Single config or array of methods
+	parameters: z.array(mcpParameterSchema).optional(),
+})
+
+export type McpMarketplaceItem = z.infer<typeof mcpMarketplaceItemSchema>
+
+/**
+ * Unified marketplace item schema using discriminated union
+ */
+export const marketplaceItemSchema = z.discriminatedUnion("type", [
+	// Mode marketplace item
+	modeMarketplaceItemSchema.extend({
+		type: z.literal("mode"),
+	}),
+	// MCP marketplace item
+	mcpMarketplaceItemSchema.extend({
+		type: z.literal("mcp"),
+	}),
+])
+
+export type MarketplaceItem = z.infer<typeof marketplaceItemSchema>
+
+/**
+ * Installation options for marketplace items
+ */
+export const installMarketplaceItemOptionsSchema = z.object({
+	target: z.enum(["global", "project"]).optional().default("project"),
+	parameters: z.record(z.string(), z.any()).optional(),
+})
+
+export type InstallMarketplaceItemOptions = z.infer<typeof installMarketplaceItemOptionsSchema>

+ 1 - 1
src/services/marketplace/MarketplaceManager.ts

@@ -4,7 +4,7 @@ import * as path from "path"
 import * as yaml from "yaml"
 import { RemoteConfigLoader } from "./RemoteConfigLoader"
 import { SimpleInstaller } from "./SimpleInstaller"
-import { MarketplaceItem, MarketplaceItemType } from "./types"
+import type { MarketplaceItem, MarketplaceItemType } from "@roo-code/types"
 import { GlobalFileNames } from "../../shared/globalFileNames"
 import { ensureSettingsDirectoryExists } from "../../utils/globalContext"
 import { t } from "../../i18n"

+ 6 - 6
src/services/marketplace/RemoteConfigLoader.ts

@@ -2,8 +2,8 @@ import axios from "axios"
 import * as yaml from "yaml"
 import { z } from "zod"
 import { getRooCodeApiUrl } from "@roo-code/cloud"
-import { MarketplaceItem, MarketplaceItemType } from "./types"
-import { modeMarketplaceItemSchema, mcpMarketplaceItemSchema } from "./schemas"
+import type { MarketplaceItem, MarketplaceItemType } from "@roo-code/types"
+import { modeMarketplaceItemSchema, mcpMarketplaceItemSchema } from "@roo-code/types"
 
 // Response schemas for YAML API responses
 const modeMarketplaceResponse = z.object({
@@ -43,8 +43,8 @@ export class RemoteConfigLoader {
 		const yamlData = yaml.parse(data)
 		const validated = modeMarketplaceResponse.parse(yamlData)
 
-		const items = validated.items.map((item) => ({
-			type: "mode" as MarketplaceItemType,
+		const items: MarketplaceItem[] = validated.items.map((item) => ({
+			type: "mode" as const,
 			...item,
 		}))
 
@@ -63,8 +63,8 @@ export class RemoteConfigLoader {
 		const yamlData = yaml.parse(data)
 		const validated = mcpMarketplaceResponse.parse(yamlData)
 
-		const items = validated.items.map((item) => ({
-			type: "mcp" as MarketplaceItemType,
+		const items: MarketplaceItem[] = validated.items.map((item) => ({
+			type: "mcp" as const,
 			...item,
 		}))
 

+ 7 - 5
src/services/marketplace/SimpleInstaller.ts

@@ -2,7 +2,7 @@ import * as vscode from "vscode"
 import * as path from "path"
 import * as fs from "fs/promises"
 import * as yaml from "yaml"
-import { MarketplaceItem, MarketplaceItemType, InstallMarketplaceItemOptions, McpParameter } from "./types"
+import type { MarketplaceItem, MarketplaceItemType, InstallMarketplaceItemOptions, McpParameter } from "@roo-code/types"
 import { GlobalFileNames } from "../../shared/globalFileNames"
 import { ensureSettingsDirectoryExists } from "../../utils/globalContext"
 
@@ -23,7 +23,7 @@ export class SimpleInstaller {
 			case "mcp":
 				return await this.installMcp(item, target, options)
 			default:
-				throw new Error(`Unsupported item type: ${item.type}`)
+				throw new Error(`Unsupported item type: ${(item as any).type}`)
 		}
 	}
 
@@ -135,7 +135,8 @@ export class SimpleInstaller {
 		}
 
 		// Merge parameters (method-specific override global)
-		const allParameters = [...(item.parameters || []), ...methodParameters]
+		const itemParameters = item.type === "mcp" ? item.parameters || [] : []
+		const allParameters = [...itemParameters, ...methodParameters]
 		const uniqueParameters = Array.from(new Map(allParameters.map((p) => [p.key, p])).values())
 
 		// Replace parameters if provided
@@ -158,7 +159,8 @@ export class SimpleInstaller {
 				methodParameters = method.parameters || []
 
 				// Re-merge parameters with the newly selected method
-				const allParametersForNewMethod = [...(item.parameters || []), ...methodParameters]
+				const itemParametersForNewMethod = item.type === "mcp" ? item.parameters || [] : []
+				const allParametersForNewMethod = [...itemParametersForNewMethod, ...methodParameters]
 				const uniqueParametersForNewMethod = Array.from(
 					new Map(allParametersForNewMethod.map((p) => [p.key, p])).values(),
 				)
@@ -239,7 +241,7 @@ export class SimpleInstaller {
 				await this.removeMcp(item, target)
 				break
 			default:
-				throw new Error(`Unsupported item type: ${item.type}`)
+				throw new Error(`Unsupported item type: ${(item as any).type}`)
 		}
 	}
 

+ 4 - 1
src/services/marketplace/__tests__/MarketplaceManager.test.ts

@@ -1,5 +1,5 @@
 import { MarketplaceManager } from "../MarketplaceManager"
-import { MarketplaceItem } from "../types"
+import type { MarketplaceItem } from "@roo-code/types"
 
 // Mock axios
 jest.mock("axios")
@@ -116,6 +116,7 @@ describe("MarketplaceManager", () => {
 					name: "Test MCP",
 					description: "A test MCP",
 					type: "mcp",
+					url: "https://example.com/mcp",
 					content: '{"command": "node", "args": ["server.js"]}',
 				},
 			]
@@ -204,6 +205,7 @@ describe("MarketplaceManager", () => {
 				name: "Test MCP",
 				description: "A test MCP",
 				type: "mcp",
+				url: "https://example.com/mcp",
 				content: '{"command": "node", "args": ["server.js"]}',
 			}
 
@@ -244,6 +246,7 @@ describe("MarketplaceManager", () => {
 				name: "Test MCP",
 				description: "A test MCP",
 				type: "mcp",
+				url: "https://example.com/mcp",
 				content: '{"command": "node", "args": ["server.js"]}',
 			}
 

+ 1 - 1
src/services/marketplace/__tests__/RemoteConfigLoader.test.ts

@@ -1,6 +1,6 @@
 import axios from "axios"
 import { RemoteConfigLoader } from "../RemoteConfigLoader"
-import { MarketplaceItemType } from "../types"
+import type { MarketplaceItemType } from "@roo-code/types"
 
 // Mock axios
 jest.mock("axios")

+ 2 - 1
src/services/marketplace/__tests__/SimpleInstaller.test.ts

@@ -2,7 +2,7 @@ import { SimpleInstaller } from "../SimpleInstaller"
 import * as fs from "fs/promises"
 import * as yaml from "yaml"
 import * as vscode from "vscode"
-import { MarketplaceItem } from "../types"
+import type { MarketplaceItem } from "@roo-code/types"
 import * as path from "path"
 
 jest.mock("fs/promises")
@@ -126,6 +126,7 @@ describe("SimpleInstaller", () => {
 			name: "Test MCP",
 			description: "A test MCP server for testing",
 			type: "mcp",
+			url: "https://example.com/mcp",
 			content: JSON.stringify({
 				command: "test-server",
 				args: ["--test"],

+ 1 - 0
src/services/marketplace/__tests__/marketplace-setting-check.test.ts

@@ -75,6 +75,7 @@ describe("Marketplace Setting Check", () => {
 				type: "mcp" as const,
 				description: "Test description",
 				content: "test content",
+				url: "https://example.com/test-mcp",
 			},
 			mpInstallOptions: { target: "project" as const },
 		}

+ 7 - 7
src/services/marketplace/__tests__/nested-parameters.spec.ts

@@ -1,6 +1,6 @@
 import { describe, it, expect } from "vitest"
-import { mcpInstallationMethodSchema, mcpMarketplaceItemYamlSchema } from "../schemas"
-import { McpInstallationMethod, McpMarketplaceItem } from "../types"
+import { mcpInstallationMethodSchema, mcpMarketplaceItemSchema } from "@roo-code/types"
+import type { McpInstallationMethod, McpMarketplaceItem } from "@roo-code/types"
 
 describe("Nested Parameters", () => {
 	describe("McpInstallationMethod Schema", () => {
@@ -95,7 +95,7 @@ describe("Nested Parameters", () => {
 				],
 			}
 
-			const result = mcpMarketplaceItemYamlSchema.parse(item)
+			const result = mcpMarketplaceItemSchema.parse(item)
 			expect(result.parameters).toHaveLength(1)
 			expect(result.parameters![0].key).toBe("api_key")
 
@@ -131,7 +131,7 @@ describe("Nested Parameters", () => {
 				],
 			}
 
-			const result = mcpMarketplaceItemYamlSchema.parse(item)
+			const result = mcpMarketplaceItemSchema.parse(item)
 			expect(result.parameters).toHaveLength(1)
 
 			const methods = result.content as McpInstallationMethod[]
@@ -160,7 +160,7 @@ describe("Nested Parameters", () => {
 				],
 			}
 
-			const result = mcpMarketplaceItemYamlSchema.parse(item)
+			const result = mcpMarketplaceItemSchema.parse(item)
 			expect(result.parameters).toBeUndefined()
 
 			const methods = result.content as McpInstallationMethod[]
@@ -182,7 +182,7 @@ describe("Nested Parameters", () => {
 				],
 			}
 
-			const result = mcpMarketplaceItemYamlSchema.parse(item)
+			const result = mcpMarketplaceItemSchema.parse(item)
 			expect(result.parameters).toBeUndefined()
 
 			const methods = result.content as McpInstallationMethod[]
@@ -221,7 +221,7 @@ describe("Nested Parameters", () => {
 			}
 
 			// This should validate successfully - the conflict resolution happens at runtime
-			const result = mcpMarketplaceItemYamlSchema.parse(item)
+			const result = mcpMarketplaceItemSchema.parse(item)
 			expect(result.parameters![0].key).toBe("version")
 
 			const methods = result.content as McpInstallationMethod[]

+ 2 - 21
src/services/marketplace/__tests__/optional-parameters.spec.ts

@@ -1,6 +1,6 @@
 import { describe, it, expect } from "vitest"
-import { mcpParameterSchema } from "../schemas"
-import { McpParameter } from "../types"
+import { mcpParameterSchema } from "@roo-code/types"
+import type { McpParameter } from "@roo-code/types"
 
 describe("Optional Parameters", () => {
 	describe("McpParameter Schema", () => {
@@ -67,23 +67,4 @@ describe("Optional Parameters", () => {
 			}).toThrow()
 		})
 	})
-
-	describe("Type Definitions", () => {
-		it("should allow optional field in McpParameter interface", () => {
-			const requiredParam: McpParameter = {
-				name: "Required Param",
-				key: "required_key",
-			}
-
-			const optionalParam: McpParameter = {
-				name: "Optional Param",
-				key: "optional_key",
-				optional: true,
-			}
-
-			// These should compile without errors
-			expect(requiredParam.optional).toBeUndefined()
-			expect(optionalParam.optional).toBe(true)
-		})
-	})
 })

+ 1 - 2
src/services/marketplace/index.ts

@@ -1,4 +1,3 @@
 export * from "./SimpleInstaller"
 export * from "./MarketplaceManager"
-export * from "./types"
-export * from "./schemas"
+export type { MarketplaceItemType } from "@roo-code/types"

+ 0 - 84
src/services/marketplace/schemas.ts

@@ -1,84 +0,0 @@
-import { z } from "zod"
-
-/**
- * Schema for MCP parameter definitions
- */
-export const mcpParameterSchema = z.object({
-	name: z.string().min(1),
-	key: z.string().min(1),
-	placeholder: z.string().optional(),
-	optional: z.boolean().optional().default(false),
-})
-
-/**
- * Schema for MCP installation method with name
- */
-export const mcpInstallationMethodSchema = z.object({
-	name: z.string().min(1),
-	content: z.string().min(1),
-	parameters: z.array(mcpParameterSchema).optional(),
-	prerequisites: z.array(z.string()).optional(),
-})
-
-/**
- * Component type validation
- */
-export const marketplaceItemTypeSchema = z.enum(["mode", "mcp"] as const)
-
-/**
- * Schema for a marketplace item (supports both mode and mcp types)
- */
-export const marketplaceItemSchema = z.object({
-	id: z.string().min(1),
-	name: z.string().min(1, "Name is required"),
-	description: z.string(),
-	type: marketplaceItemTypeSchema,
-	author: z.string().optional(),
-	authorUrl: z.string().url("Author URL must be a valid URL").optional(),
-	tags: z.array(z.string()).optional(),
-	content: z.union([z.string().min(1), z.array(mcpInstallationMethodSchema)]), // Embedded content (YAML for modes, JSON for mcps, or named methods)
-	prerequisites: z.array(z.string()).optional(),
-})
-
-/**
- * Local marketplace config schema (JSON format)
- */
-export const marketplaceConfigSchema = z.object({
-	items: z.record(z.string(), marketplaceItemSchema),
-})
-
-/**
- * Local marketplace YAML config schema (uses any for items since they're validated separately by type)
- */
-export const marketplaceYamlConfigSchema = z.object({
-	items: z.array(z.any()), // Items are validated separately by type-specific schemas
-})
-
-// Schemas for YAML files (without type field, as type is added programmatically)
-export const modeMarketplaceItemYamlSchema = z.object({
-	id: z.string(),
-	name: z.string(),
-	description: z.string(),
-	author: z.string().optional(),
-	authorUrl: z.string().url().optional(),
-	tags: z.array(z.string()).optional(),
-	content: z.string(),
-	prerequisites: z.array(z.string()).optional(),
-})
-
-export const mcpMarketplaceItemYamlSchema = z.object({
-	id: z.string(),
-	name: z.string(),
-	description: z.string(),
-	author: z.string().optional(),
-	authorUrl: z.string().url().optional(),
-	url: z.string().url(), // Required url field
-	tags: z.array(z.string()).optional(),
-	content: z.union([z.string(), z.array(mcpInstallationMethodSchema)]),
-	parameters: z.array(mcpParameterSchema).optional(),
-	prerequisites: z.array(z.string()).optional(),
-})
-
-// Export aliases for backward compatibility (these are the same as the YAML schemas)
-export const modeMarketplaceItemSchema = modeMarketplaceItemYamlSchema
-export const mcpMarketplaceItemSchema = mcpMarketplaceItemYamlSchema

+ 0 - 92
src/services/marketplace/types.ts

@@ -1,92 +0,0 @@
-/**
- * Supported component types
- */
-export type MarketplaceItemType = "mode" | "mcp"
-
-/**
- * Local marketplace config types
- */
-export interface MarketplaceConfig<T = any> {
-	items: Record<string, T>
-}
-
-export interface MarketplaceYamlConfig<T = any> {
-	items: T[]
-}
-
-export interface ModeMarketplaceItem {
-	id: string
-	name: string
-	description: string
-	author?: string
-	authorUrl?: string
-	tags?: string[]
-	content: string // Embedded YAML content for .roomodes
-	prerequisites?: string[]
-}
-
-export interface McpParameter {
-	name: string
-	key: string
-	placeholder?: string
-	optional?: boolean // Defaults to false if not provided
-}
-
-export interface McpInstallationMethod {
-	name: string
-	content: string
-	parameters?: McpParameter[]
-	prerequisites?: string[]
-}
-
-export interface McpMarketplaceItem {
-	id: string
-	name: string
-	description: string
-	author?: string
-	authorUrl?: string
-	url: string // Required url field
-	tags?: string[]
-	content: string | McpInstallationMethod[] // Can be a single config or array of named methods
-	parameters?: McpParameter[]
-	prerequisites?: string[]
-}
-
-/**
- * Unified marketplace item for UI
- */
-export interface MarketplaceItem {
-	id: string
-	name: string
-	description: string
-	type: MarketplaceItemType
-	author?: string
-	authorUrl?: string
-	url?: string // Optional - only MCPs have url
-	tags?: string[]
-	content: string | McpInstallationMethod[] // Can be a single config or array of named methods
-	parameters?: McpParameter[] // Optional parameters for MCPs
-	prerequisites?: string[]
-}
-
-export interface InstallMarketplaceItemOptions {
-	/**
-	 * Specify the target scope
-	 *
-	 * @default 'project'
-	 */
-	target?: "global" | "project"
-	/**
-	 * Parameters provided by the user for configurable marketplace items
-	 */
-	parameters?: Record<string, any>
-}
-
-export interface RemoveInstalledMarketplaceItemOptions {
-	/**
-	 * Specify the target scope
-	 *
-	 * @default 'project'
-	 */
-	target?: "global" | "project"
-}

+ 1 - 1
src/shared/ExtensionMessage.ts

@@ -16,7 +16,7 @@ import { GitCommit } from "../utils/git"
 import { McpServer } from "./mcp"
 import { Mode } from "./modes"
 import { RouterModels } from "./api"
-import { MarketplaceItem } from "../services/marketplace/types"
+import type { MarketplaceItem } from "@roo-code/types"
 
 // Indexing status types
 export interface IndexingStatus {

+ 9 - 4
src/shared/WebviewMessage.ts

@@ -1,8 +1,13 @@
 import { z } from "zod"
 
-import type { ProviderSettings, PromptComponent, ModeConfig } from "@roo-code/types"
-import { InstallMarketplaceItemOptions, MarketplaceItem } from "../services/marketplace/types"
-import { marketplaceItemSchema } from "../services/marketplace/schemas"
+import type {
+	ProviderSettings,
+	PromptComponent,
+	ModeConfig,
+	InstallMarketplaceItemOptions,
+	MarketplaceItem,
+} from "@roo-code/types"
+import { marketplaceItemSchema } from "@roo-code/types"
 
 import { Mode } from "./modes"
 
@@ -229,7 +234,7 @@ export interface IndexClearedPayload {
 }
 
 export const installMarketplaceItemWithParametersPayloadSchema = z.object({
-	item: marketplaceItemSchema.strict(),
+	item: marketplaceItemSchema,
 	parameters: z.record(z.string(), z.any()),
 })
 

+ 1 - 1
webview-ui/src/components/marketplace/MarketplaceViewStateManager.ts

@@ -11,7 +11,7 @@
  * 3. Using minimal state updates to avoid resetting scroll position
  */
 
-import { MarketplaceItem } from "../../../../src/services/marketplace/types"
+import { MarketplaceItem } from "@roo-code/types"
 import { vscode } from "../../utils/vscode"
 import { WebviewMessage } from "../../../../src/shared/WebviewMessage"
 

+ 3 - 3
webview-ui/src/components/marketplace/components/MarketplaceInstallModal.tsx

@@ -1,5 +1,5 @@
 import React, { useState, useMemo, useEffect } from "react"
-import { MarketplaceItem, McpParameter, McpInstallationMethod } from "../../../../../src/services/marketplace/types"
+import { MarketplaceItem, McpParameter, McpInstallationMethod } from "@roo-code/types"
 import { vscode } from "@/utils/vscode"
 import { useAppTranslation } from "@/i18n/TranslationContext"
 import {
@@ -61,7 +61,7 @@ export const MarketplaceInstallModal: React.FC<MarketplaceInstallModalProps> = (
 	const effectiveParameters = useMemo(() => {
 		if (!item) return []
 
-		const globalParams = item.parameters || []
+		const globalParams = item.type === "mcp" ? item.parameters || [] : []
 		let methodParams: McpParameter[] = []
 
 		// Get method-specific parameters if content is an array
@@ -100,7 +100,7 @@ export const MarketplaceInstallModal: React.FC<MarketplaceInstallModalProps> = (
 	React.useEffect(() => {
 		if (item) {
 			// Get effective parameters for current method
-			const globalParams = item.parameters || []
+			const globalParams = item.type === "mcp" ? item.parameters || [] : []
 			let methodParams: McpParameter[] = []
 
 			if (Array.isArray(item.content)) {

+ 2 - 2
webview-ui/src/components/marketplace/components/MarketplaceItemCard.tsx

@@ -1,5 +1,5 @@
 import React, { useMemo, useState } from "react"
-import { MarketplaceItem } from "../../../../../src/services/marketplace/types"
+import { MarketplaceItem } from "@roo-code/types"
 import { vscode } from "@/utils/vscode"
 import { ViewState } from "../MarketplaceViewStateManager"
 import { useAppTranslation } from "@/i18n/TranslationContext"
@@ -54,7 +54,7 @@ export const MarketplaceItemCard: React.FC<MarketplaceItemCardProps> = ({ item,
 					<div className="flex gap-2 items-start">
 						<div>
 							<h3 className="text-lg font-semibold text-vscode-foreground mt-0 mb-1 leading-none">
-								{item.url && isValidUrl(item.url) ? (
+								{item.type === "mcp" && item.url && isValidUrl(item.url) ? (
 									<Button
 										variant="link"
 										className="p-0 h-auto text-lg font-semibold text-vscode-foreground hover:underline"

+ 2 - 1
webview-ui/src/components/marketplace/components/__tests__/MarketplaceInstallModal-optional-params.test.tsx

@@ -1,7 +1,7 @@
 import React from "react"
 import { render, screen, fireEvent, waitFor } from "@testing-library/react"
 import { MarketplaceInstallModal } from "../MarketplaceInstallModal"
-import { MarketplaceItem } from "../../../../../../src/services/marketplace/types"
+import { MarketplaceItem } from "@roo-code/types"
 
 // Mock vscode
 const mockPostMessage = jest.fn()
@@ -39,6 +39,7 @@ describe("MarketplaceInstallModal - Optional Parameters", () => {
 		name: "Test MCP",
 		description: "Test MCP with parameters",
 		type: "mcp",
+		url: "https://example.com/test-mcp",
 		content: '{"test-server": {"command": "test", "args": ["--key", "{{api_key}}", "--endpoint", "{{endpoint}}"]}}',
 		parameters,
 	})

+ 2 - 1
webview-ui/src/components/marketplace/components/__tests__/MarketplaceInstallModal.test.tsx

@@ -1,7 +1,7 @@
 import React from "react"
 import { render, screen, fireEvent, waitFor } from "@testing-library/react"
 import { MarketplaceInstallModal } from "../MarketplaceInstallModal"
-import { MarketplaceItem } from "../../../../../../src/services/marketplace/types"
+import { MarketplaceItem } from "@roo-code/types"
 
 // Mock the vscode module before importing the component
 jest.mock("@/utils/vscode", () => ({
@@ -44,6 +44,7 @@ describe("MarketplaceInstallModal - Nested Parameters", () => {
 		name: "Test MCP Server",
 		description: "A test MCP server",
 		type: "mcp",
+		url: "https://example.com/test-mcp",
 		author: "Test Author",
 		tags: ["test"],
 		// Global parameters

+ 1 - 1
webview-ui/src/components/marketplace/components/__tests__/MarketplaceItemCard.test.tsx

@@ -2,7 +2,7 @@ import { render, screen } from "@testing-library/react"
 import userEvent from "@testing-library/user-event"
 import { MarketplaceItemCard } from "../MarketplaceItemCard"
 import { vscode } from "@/utils/vscode"
-import { MarketplaceItem } from "../../../../../../src/services/marketplace/types"
+import { MarketplaceItem } from "@roo-code/types"
 import { TooltipProvider } from "@/components/ui/tooltip"
 // Mock vscode API
 jest.mock("@/utils/vscode", () => ({

+ 4 - 1
webview-ui/src/components/marketplace/utils/__tests__/grouping.test.ts

@@ -1,5 +1,5 @@
 import { groupItemsByType, formatItemText, getTotalItemCount, getUniqueTypes } from "../grouping"
-import { MarketplaceItem } from "../../../../../../src/services/marketplace/types"
+import { MarketplaceItem } from "@roo-code/types"
 
 describe("grouping utilities", () => {
 	const mockItems: MarketplaceItem[] = [
@@ -8,6 +8,7 @@ describe("grouping utilities", () => {
 			name: "Test Server",
 			description: "A test MCP server",
 			type: "mcp",
+			url: "https://example.com/test-server",
 			content: "test content",
 		},
 		{
@@ -22,6 +23,7 @@ describe("grouping utilities", () => {
 			name: "Another Server",
 			description: "Another test MCP server",
 			type: "mcp",
+			url: "https://example.com/another-server",
 			content: "test content",
 		},
 	]
@@ -50,6 +52,7 @@ describe("grouping utilities", () => {
 					name: "",
 					description: "",
 					type: "mcp",
+					url: "https://example.com/test-item",
 					content: "test content",
 				},
 			]

+ 1 - 1
webview-ui/src/components/marketplace/utils/grouping.ts

@@ -1,4 +1,4 @@
-import { MarketplaceItem } from "../../../../../src/services/marketplace/types"
+import { MarketplaceItem } from "@roo-code/types"
 
 export interface GroupedItems {
 	[type: string]: {