Showing the changes to plugins (3 of 5 files). Show all
Unified · Split
| @@ -55,6 +55,9 @@ type McpExecutorExtension = { · 54 unmodified lines | ||
| 55 | 55 | updateSource: ( |
| 56 | 56 | input: McpUpdateSourceInput, |
| 57 | 57 | ) => Effect.Effect<Source, Error>; |
| 58 | + refreshSource: ( | |
| 59 | + sourceId: Source["id"], | |
| 60 | + ) => Effect.Effect<Source, Error>; | |
| 58 | 61 | removeSource: ( |
| 59 | 62 | sourceId: Source["id"], |
| 60 | 63 | ) => Effect.Effect<boolean, Error>; |
| @@ -117,6 +120,14 @@ export const McpHttpGroup = HttpApiGroup.make("mcp") · 56 unmodified lines | ||
| 117 | 120 | .addError(ControlPlaneNotFoundError) |
| 118 | 121 | .addError(ControlPlaneStorageError), |
| 119 | 122 | ) |
| 123 | + .add( | |
| 124 | + HttpApiEndpoint.post("refreshSource")`/workspaces/${workspaceIdParam}/plugins/mcp/sources/${sourceIdParam}/refresh` | |
| 125 | + .addSuccess(SourceSchema) | |
| 126 | + .addError(ControlPlaneBadRequestError) | |
| 127 | + .addError(ControlPlaneForbiddenError) | |
| 128 | + .addError(ControlPlaneNotFoundError) | |
| 129 | + .addError(ControlPlaneStorageError), | |
| 130 | + ) | |
| 120 | 131 | .add( |
| 121 | 132 | HttpApiEndpoint.del("removeSource")`/workspaces/${workspaceIdParam}/plugins/mcp/sources/${sourceIdParam}` |
| 122 | 133 | .addSuccess(Schema.Struct({ removed: Schema.Boolean })) |
| @@ -284,6 +295,17 @@ export const mcpHttpPlugin = (): ExecutorHttpPlugin< · 161 unmodified lines | ||
| 284 | 295 | ), |
| 285 | 296 | ) |
| 286 | 297 | ) |
| 298 | + .handle("refreshSource", ({ path }) => | |
| 299 | + resolveRequestedLocalWorkspace( | |
| 300 | + "mcp.refreshSource", | |
| 301 | + path.workspaceId, | |
| 302 | + ).pipe( | |
| 303 | + Effect.flatMap(() => executor.mcp.refreshSource(path.sourceId)), | |
| 304 | + Effect.mapError((cause) => | |
| 305 | + mapPluginStorageError("mcp.refreshSource", cause) | |
| 306 | + ), | |
| 307 | + ) | |
| 308 | + ) | |
| 287 | 309 | .handle("removeSource", ({ path }) => |
| 288 | 310 | resolveRequestedLocalWorkspace( |
| 289 | 311 | "mcp.removeSource", |
| @@ -733,6 +733,25 @@ export function McpDetailPage(props: { · 732 unmodified lines | ||
| 733 | 733 | client.mutation("mcp", "removeSource"), |
| 734 | 734 | { mode: "promise" }, |
| 735 | 735 | ); |
| 736 | + const refreshSource = useAtomSet( | |
| 737 | + client.mutation("mcp", "refreshSource"), | |
| 738 | + { mode: "promise" }, | |
| 739 | + ); | |
| 740 | + const refreshMutation = useExecutorMutation<Source["id"], Source>(async (sourceId) => | |
| 741 | + refreshSource({ | |
| 742 | + path: { | |
| 743 | + workspaceId: props.source.scopeId, | |
| 744 | + sourceId, | |
| 745 | + }, | |
| 746 | + reactivityKeys: { | |
| 747 | + sources: [props.source.scopeId], | |
| 748 | + source: [props.source.scopeId, sourceId], | |
| 749 | + sourceInspection: [props.source.scopeId, sourceId], | |
| 750 | + sourceInspectionTool: [props.source.scopeId, sourceId], | |
| 751 | + sourceDiscovery: [props.source.scopeId, sourceId], | |
| 752 | + }, | |
| 753 | + }) | |
| 754 | + ); | |
| 736 | 755 | const [confirmDelete, setConfirmDelete] = useState(false); |
| 737 | 756 | const [isDeleting, setIsDeleting] = useState(false); |
| 738 | 757 | const configResult = useAtomValue( |
| @@ -815,6 +834,19 @@ export function McpDetailPage(props: { · 76 unmodified lines | ||
| 815 | 834 | <> |
| 816 | 835 | <Button |
| 817 | 836 | variant="outline" |
| 837 | + size="sm" | |
| 838 | + type="button" | |
| 839 | + onClick={() => { | |
| 840 | + void refreshMutation.mutateAsync(props.source.id); | |
| 841 | + }} | |
| 842 | + disabled={refreshMutation.status === "pending"} | |
| 843 | + > | |
| 844 | + {refreshMutation.status === "pending" ? "Refreshing..." : "Refresh"} | |
| 845 | + </Button> | |
| 846 | + <Button | |
| 847 | + variant="outline" | |
| 848 | + size="sm" | |
| 849 | + type="button" | |
| 818 | 850 | onClick={() => |
| 819 | 851 | void navigation.edit(props.source.id)} |
| 820 | 852 | > |
| @@ -163,6 +163,9 @@ export type McpSdk = { · 162 unmodified lines | ||
| 163 | 163 | updateSource: ( |
| 164 | 164 | input: McpUpdateSourceInput, |
| 165 | 165 | ) => Effect.Effect<Source, Error>; |
| 166 | + refreshSource: ( | |
| 167 | + sourceId: Source["id"], | |
| 168 | + ) => Effect.Effect<Source, Error>; | |
| 166 | 169 | removeSource: ( |
| 167 | 170 | sourceId: Source["id"], |
| 168 | 171 | ) => Effect.Effect<boolean, Error>; |
| @@ -948,6 +951,13 @@ export const mcpSdkPlugin = ( · 779 unmodified lines | ||
| 948 | 951 | outputSchema: SourceSchema, |
| 949 | 952 | execute: ({ args, source }) => source.updateSource(args), |
| 950 | 953 | }, |
| 954 | + { | |
| 955 | + name: "refreshSource", | |
| 956 | + description: "Refresh an MCP source and resync its catalog.", | |
| 957 | + inputSchema: McpSourceIdInputSchema, | |
| 958 | + outputSchema: SourceSchema, | |
| 959 | + execute: ({ args, source }) => source.refreshSource(args.sourceId), | |
| 960 | + }, | |
| 951 | 961 | { |
| 952 | 962 | name: "removeSource", |
| 953 | 963 | description: "Remove an MCP source and its stored plugin data.", |
| @@ -1092,6 +1102,8 @@ export const mcpSdkPlugin = ( · 138 unmodified lines | ||
| 1092 | 1102 | provideRuntime(source.createSource(input)), |
| 1093 | 1103 | updateSource: (input) => |
| 1094 | 1104 | provideRuntime(source.updateSource(input)), |
| 1105 | + refreshSource: (sourceId) => | |
| 1106 | + provideRuntime(source.refreshSource(sourceId)), | |
| 1095 | 1107 | removeSource: (sourceId) => |
| 1096 | 1108 | provideRuntime(source.removeSource(sourceId)), |
| 1097 | 1109 | startOAuth: (input) => |