molecule-core/mcp-server/src/tools/plugins.ts
Hongming Wang 1512e7ce62 refactor(mcp-server): split 1697-line index.ts into per-domain modules
Pure mechanical split, no behavior changes. Pulls the 70+ tool handlers
out of one monolith into api.ts (PLATFORM_URL + apiCall) plus 12
tools/*.ts files grouped by domain (workspaces, agents, secrets, files,
memory, plugins, channels, delegation, schedules, approvals, discovery,
remote_agents). Each module exports its handlers and a
registerXxxTools(srv) function; createServer() wires them up.

index.ts drops from 1697 → 89 lines. Largest new file is 183 lines.
All handlers still re-exported from index.ts so existing tests that
import them via "../index.js" keep working. Build clean; jest results
unchanged from pre-refactor baseline.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 13:27:04 -07:00

107 lines
3.8 KiB
TypeScript

import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import { apiCall } from "../api.js";
export async function handleListPluginRegistry() {
const data = await apiCall("GET", "/plugins");
return { content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }] };
}
export async function handleListInstalledPlugins(params: { workspace_id: string }) {
const data = await apiCall("GET", `/workspaces/${params.workspace_id}/plugins`);
return { content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }] };
}
export async function handleInstallPlugin(params: { workspace_id: string; source: string }) {
const { workspace_id, source } = params;
const data = await apiCall("POST", `/workspaces/${workspace_id}/plugins`, { source });
return { content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }] };
}
export async function handleUninstallPlugin(params: { workspace_id: string; name: string }) {
const { workspace_id, name } = params;
const data = await apiCall("DELETE", `/workspaces/${workspace_id}/plugins/${name}`);
return { content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }] };
}
export async function handleListPluginSources() {
const data = await apiCall("GET", "/plugins/sources");
return { content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }] };
}
export async function handleListAvailablePlugins(params: { workspace_id: string }) {
const data = await apiCall("GET", `/workspaces/${params.workspace_id}/plugins/available`);
return { content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }] };
}
export async function handleCheckPluginCompatibility(params: {
workspace_id: string;
runtime: string;
}) {
const { workspace_id, runtime } = params;
const data = await apiCall(
"GET",
`/workspaces/${workspace_id}/plugins/compatibility?runtime=${encodeURIComponent(runtime)}`,
);
return { content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }] };
}
export function registerPluginTools(srv: McpServer) {
srv.tool("list_plugin_registry", "List all available plugins from the registry", {}, handleListPluginRegistry);
srv.tool(
"list_installed_plugins",
"List plugins installed in a workspace",
{ workspace_id: z.string().describe("Workspace ID") },
handleListInstalledPlugins
);
srv.tool(
"install_plugin",
"Install a plugin into a workspace from any registered source (auto-restarts). Use GET /plugins/sources to list schemes.",
{
workspace_id: z.string().describe("Workspace ID"),
source: z
.string()
.describe(
"Source URL: 'local://<name>' for platform registry, 'github://<owner>/<repo>[#<ref>]' for GitHub, or any registered scheme."
),
},
handleInstallPlugin
);
srv.tool(
"uninstall_plugin",
"Remove a plugin from a workspace (auto-restarts)",
{
workspace_id: z.string().describe("Workspace ID"),
name: z.string().describe("Plugin name to remove"),
},
handleUninstallPlugin
);
srv.tool(
"list_plugin_sources",
"List registered plugin install-source schemes (e.g. local, github).",
{},
handleListPluginSources,
);
srv.tool(
"list_available_plugins",
"List plugins from the registry filtered to ones supported by this workspace's runtime.",
{ workspace_id: z.string() },
handleListAvailablePlugins,
);
srv.tool(
"check_plugin_compatibility",
"Preflight check: which installed plugins would break if this workspace switched runtime to <runtime>?",
{
workspace_id: z.string(),
runtime: z.string().describe("Target runtime (claude-code, deepagents, langgraph, ...)"),
},
handleCheckPluginCompatibility,
);
}