diff --git a/packages/client/src/promise/generated/types.ts b/packages/client/src/promise/generated/types.ts index 6d8ca4a5917..399b6932a19 100644 --- a/packages/client/src/promise/generated/types.ts +++ b/packages/client/src/promise/generated/types.ts @@ -2133,6 +2133,7 @@ export type SessionMessagesResponse = { export type IntegrationInfo = { id: string name: string + metadata?: { [x: string]: any } methods: Array connections: Array } diff --git a/packages/core/src/integration.ts b/packages/core/src/integration.ts index 0fe1cb31826..21e0dc58669 100644 --- a/packages/core/src/integration.ts +++ b/packages/core/src/integration.ts @@ -361,6 +361,7 @@ const layer = Layer.effect( Info.make({ id: entry.ref.id, name: entry.ref.name, + ...(entry.ref.metadata === undefined ? {} : { metadata: entry.ref.metadata }), methods: entry.methods, connections, }) diff --git a/packages/core/src/mcp/index.ts b/packages/core/src/mcp/index.ts index 95d29acd1ef..78362cc3305 100644 --- a/packages/core/src/mcp/index.ts +++ b/packages/core/src/mcp/index.ts @@ -228,6 +228,7 @@ export const layer = (options?: Options) => .transform((draft) => { draft.update(integrationID, (ref) => { ref.name = name + ref.metadata = { source: "mcp" } }) draft.method.update({ integrationID, diff --git a/packages/core/test/integration.test.ts b/packages/core/test/integration.test.ts index edfdae01248..0ece7d2459a 100644 --- a/packages/core/test/integration.test.ts +++ b/packages/core/test/integration.test.ts @@ -52,10 +52,21 @@ describe("Integration", () => { const openai = Integration.ID.make("openai") yield* integrations - .transform((editor) => editor.update(openai, (integration) => (integration.name = "OpenAI"))) + .transform((editor) => + editor.update(openai, (integration) => { + integration.name = "OpenAI" + integration.metadata = { source: "plugin", featured: true } + }), + ) .pipe(Scope.provide(scope)) expect(yield* integrations.get(openai)).toEqual( - Integration.Info.make({ id: openai, name: "OpenAI", methods: [], connections: [] }), + Integration.Info.make({ + id: openai, + name: "OpenAI", + metadata: { source: "plugin", featured: true }, + methods: [], + connections: [], + }), ) yield* Scope.close(scope, Exit.void) diff --git a/packages/schema/src/integration.ts b/packages/schema/src/integration.ts index 0afb8199c67..299dc7718dd 100644 --- a/packages/schema/src/integration.ts +++ b/packages/schema/src/integration.ts @@ -59,11 +59,13 @@ export interface Ref extends Schema.Schema.Type {} export const Ref = Schema.Struct({ id: ID, name: Schema.String, + metadata: optional(Schema.Record(Schema.String, Schema.Any)), }).annotate({ identifier: "Integration.Ref" }) export const Info = Schema.Struct({ id: ID, name: Schema.String, + metadata: optional(Schema.Record(Schema.String, Schema.Any)), methods: Schema.Array(Method), connections: Schema.Array(Connection.Info), }).annotate({ identifier: "Integration.Info" }) diff --git a/packages/tui/src/component/dialog-integration.tsx b/packages/tui/src/component/dialog-integration.tsx index b36202e7e67..b476d3006d0 100644 --- a/packages/tui/src/component/dialog-integration.tsx +++ b/packages/tui/src/component/dialog-integration.tsx @@ -45,6 +45,7 @@ const SUBMIT = Symbol("submit") export function integrationOptions(list: IntegrationInfo[]) { return list.toSorted( (a, b) => + Number(b.metadata?.source === "mcp") - Number(a.metadata?.source === "mcp") || (INTEGRATION_PRIORITY[a.id] ?? 99) - (INTEGRATION_PRIORITY[b.id] ?? 99) || a.name.localeCompare(b.name) || a.id.localeCompare(b.id), @@ -103,6 +104,7 @@ export function DialogIntegration( let category = "Services" if (integration.id in INTEGRATION_PRIORITY) category = "Popular" if (provider) category = "Web search" + if (integration.metadata?.source === "mcp") category = "MCP" return { title: integration.name, value: integration.id, diff --git a/packages/tui/test/cli/cmd/tui/integration-options.test.ts b/packages/tui/test/cli/cmd/tui/integration-options.test.ts index a07788248b6..988f222c722 100644 --- a/packages/tui/test/cli/cmd/tui/integration-options.test.ts +++ b/packages/tui/test/cli/cmd/tui/integration-options.test.ts @@ -24,6 +24,16 @@ describe("integrationOptions", () => { ]).map((item) => item.id), ).toEqual(["openai", "anthropic", "mistral", "custom-z"]) }) + + test("keeps MCP integrations above popular integrations without relying on their IDs", () => { + expect( + integrationOptions([ + integration({ id: "openai", name: "OpenAI" }), + integration({ id: "linear", name: "Linear", metadata: { source: "mcp" } }), + integration({ id: "github", name: "GitHub", metadata: { source: "mcp" } }), + ]).map((item) => item.id), + ).toEqual(["github", "linear", "openai"]) + }) }) describe("connectMethods", () => {