@xopcai/xopc 0.0.224 → 0.0.225
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/demo-memory/src/index.js +10 -1
- package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{activity-store--GBciH10.js → activity-store-CtTYnku4.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-K7V4XXt7.js → agent-avatar-dicebear-dizuqu_4.js} +1 -1
- package/dist/gateway/static/root/assets/{agents-BsxTpXyq.js → agents-DeEEFZJ4.js} +1 -1
- package/dist/gateway/static/root/assets/{api-HoIz_ija.js → api-CLRMz2BT.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-xQCmkAHh.js → app-management-settings-panel-Cnk-DtQh.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-BRoeA4kU.js → appearance-settings-wP0rogVI.js} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-BXgpBA8w.js → apps-page-Db5YNHVM.js} +1 -1
- package/dist/gateway/static/root/assets/{archive-plugin-CteCVsBP.js → archive-plugin-Cpzsm-DM.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-D7xNA2jB.js → attachment-load-Bd2OOoEK.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-BD1vK7r5.js → automations-page-DNqhguyk.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-workspace-wrgf-z7D.js → automations-workspace-CNT05YTb.js} +1 -1
- package/dist/gateway/static/root/assets/{binary-plugins-C3DaJa0W.js → binary-plugins-Dcma5HdI.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-lTkcHTve.js → block-editor-D-B8ThwK.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-settings-page-zhzNkeVG.js → browser-settings-page-UbDj3LIq.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflow-inputs-1UZ0vnIy.js → browser-workflow-inputs-BAPZIXrs.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflows-page-BHuJOF4M.js → browser-workflows-page-DHtaSKEh.js} +1 -1
- package/dist/gateway/static/root/assets/{capabilities-settings-panel-DuCmg2Ej.js → capabilities-settings-panel-CiO152QS.js} +1 -1
- package/dist/gateway/static/root/assets/{capability-presets-api-yNqTIuyd.js → capability-presets-api-zsZQ7im3.js} +1 -1
- package/dist/gateway/static/root/assets/{capability-presets-settings-panel-DjiP3mQQ.js → capability-presets-settings-panel-Bc_hRwfL.js} +1 -1
- package/dist/gateway/static/root/assets/{channel-recipient-api-krezGsKc.js → channel-recipient-api-Cp8iaaXp.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-settings-B4AtvQHk.js → channels-settings-CFW7zBoT.js} +1 -1
- package/dist/gateway/static/root/assets/channels-status-swr-5rNVq7iI.js +1 -0
- package/dist/gateway/static/root/assets/{chat-terminal-dock-BRrL2iHA.js → chat-terminal-dock-Dr6Rq2ln.js} +1 -1
- package/dist/gateway/static/root/assets/connectors-page-DLBr5nre.js +2 -0
- package/dist/gateway/static/root/assets/{cron-expression-Bl-2DzBQ.js → cron-expression-BiXrpzmo.js} +1 -1
- package/dist/gateway/static/root/assets/{date-picker-CxTl6Wlz.js → date-picker-BPuRtwKt.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-DSl0mOPa.js → dependency-picker-BNC_W7wI.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-DTeCmCdb.js → desktop-pet-DzOpt5nI.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-BNebxg0V.js → desktop-pet-settings-BW0brCvH.js} +1 -1
- package/dist/gateway/static/root/assets/{directory-picker-path-field-Dn9XpmXY.js → directory-picker-path-field-Baml0uTS.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-D-J-eOTb.js → extension-debug-page-CBXyKmfS.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-CpST24nU.js → extension-page-BBhcr_SZ.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-4nQXFnFq.js → extension-settings-page-4rwWpN9_.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-BHWHduDi.js → gateway-config-api-Dg-BlBe4.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-yUxMMVjK.js → gateway-config-swr-Du0MvK9s.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-BimMKmkM.js → gateway-settings-BOuYZOYe.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-9mrsL84j.js → gateway-startup-retry-JbjcHCaN.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-MUJ3mEC9.js → heartbeat-settings-Dq4YAlSx.js} +1 -1
- package/dist/gateway/static/root/assets/{home-page-DSM6aPHF.js → home-page-BIXkO0Ck.js} +1 -1
- package/dist/gateway/static/root/assets/{image-generation-api-CgFAGDi8.js → image-generation-api-G2tfPvKP.js} +1 -1
- package/dist/gateway/static/root/assets/{index-B3zYJBhK.js → index-Csccu8sa.js} +11 -11
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-6Ar5rfX4.js → keyboard-shortcuts-settings-L1Vtxgp9.js} +1 -1
- package/dist/gateway/static/root/assets/{local-app-workbench-page-tzM0wTL8.js → local-app-workbench-page-D-eacBcO.js} +1 -1
- package/dist/gateway/static/root/assets/{local-apps-page-B5n-x544.js → local-apps-page--thlkBLS.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-CPylQjH9.js → locale-store-DqJz-cOR.js} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-CgoQlera.js → logs-page-BRCglHvd.js} +1 -1
- package/dist/gateway/static/root/assets/{management-settings-CXBLyU-0.js → management-settings-p55fR4XO.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-split-CtmQemJi.js → markdown-split-DwMcRlBR.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-view-CUsob4Pz.js → markdown-view-CTB9u15e.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-Dsd-IEOW.js → media-plugins-O6H3GZn7.js} +1 -1
- package/dist/gateway/static/root/assets/{messages-B82nsi9k.js → messages-CeydamsI.js} +3 -3
- package/dist/gateway/static/root/assets/{notes-api-CfKZYrBC.js → notes-api-CrjQbmk1.js} +1 -1
- package/dist/gateway/static/root/assets/{notes-page-BKbOTE2n.js → notes-page-miO9ig9C.js} +1 -1
- package/dist/gateway/static/root/assets/{notes-workbench-BScELo01.js → notes-workbench-_13lmvmF.js} +2 -2
- package/dist/gateway/static/root/assets/{product-open-page-DqB9bsDB.js → product-open-page-BOu07nXf.js} +1 -1
- package/dist/gateway/static/root/assets/{project-detail-page-DUoyty8X.js → project-detail-page-BStRkOQr.js} +1 -1
- package/dist/gateway/static/root/assets/{projects-page-PeXUdGdO.js → projects-page-CY03RxVr.js} +1 -1
- package/dist/gateway/static/root/assets/{registry-api-B_5D8epF.js → registry-api-Bf_HDLUJ.js} +1 -1
- package/dist/gateway/static/root/assets/{remote-access-hub-sHho-uXP.js → remote-access-hub-B19llkld.js} +1 -1
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-DBTH_t0O.js → runtime-tools-settings-panel-DthuRqUH.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-CqMKAwV0.js → schema-form-8W8PhXxa.js} +1 -1
- package/dist/gateway/static/root/assets/{sessions-page-DyvNgaP9.js → sessions-page-BDA2qbTd.js} +1 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-BONIDX4v.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-dPriuuYq.js → settings-form-section-CrsKGYiG.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-loading-skeleton-B-Mbm8Va.js → settings-loading-skeleton-WJtI0AAq.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-Dyj3w-Ml.js → settings-page-PCjwRF47.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-C4FxY5J3.js → setup-status-panel-D65CwlNC.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-emEdx7YL.js → share-preview-page-BGtvLLeZ.js} +1 -1
- package/dist/gateway/static/root/assets/{shares-settings-BQBVq-sN.js → shares-settings-CdzVKrBl.js} +1 -1
- package/dist/gateway/static/root/assets/skill-reload-api-CsRWid5h.js +1 -0
- package/dist/gateway/static/root/assets/{skills-page-BNtYnrRT.js → skills-page-C_npyryI.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page.utils-DjnbNFs5.js → skills-page.utils-C46Sd78k.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-DDStf-jZ.js → system-settings-panel-DomTLwki.js} +1 -1
- package/dist/gateway/static/root/assets/{task-detail-page-ZVwr8KbS.js → task-detail-page-B6YFX7kK.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-BN-32Fz5.js → theme-store-Ce7wq__X.js} +1 -1
- package/dist/gateway/static/root/assets/{use-autosave-C2mKZ-ua.js → use-autosave-Do9mCRcY.js} +1 -1
- package/dist/gateway/static/root/assets/{user-context-page-CHjIinCW.js → user-context-page-CiCQA40E.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-api-key-field-D7OHeQby.js → voice-api-key-field-Bc5p-0tX.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-CIiXie7F.js → work-discovery-overlay-BieqsmT1.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-9_dAGW3_.js → workflow-run-setup-panel-DVj8iYvm.js} +1 -1
- package/dist/gateway/static/root/assets/{workflows-page-DXpYJxao.js → workflows-page-AG04TTuH.js} +1 -1
- package/dist/gateway/static/root/index.html +10 -10
- package/dist/package.js +1 -1
- package/dist/src/agent/embedded/run-turn.js +2 -0
- package/dist/src/agent/mcp/bundle-mcp-config.d.ts +9 -1
- package/dist/src/agent/mcp/bundle-mcp-config.js +11 -15
- package/dist/src/agent/mcp/embedded-mcp.d.ts +1 -1
- package/dist/src/agent/mcp/index.d.ts +1 -0
- package/dist/src/agent/mcp/index.js +7 -1
- package/dist/src/agent/mcp/mcp-http.d.ts +4 -0
- package/dist/src/agent/mcp/mcp-http.js +25 -1
- package/dist/src/agent/mcp/mcp-transport-config.d.ts +4 -0
- package/dist/src/agent/mcp/mcp-transport-config.js +1 -0
- package/dist/src/agent/mcp/mcp-transport.d.ts +7 -1
- package/dist/src/agent/mcp/mcp-transport.js +38 -11
- package/dist/src/agent/mcp/oauth/index.d.ts +6 -0
- package/dist/src/agent/mcp/oauth/index.js +6 -0
- package/dist/src/agent/mcp/oauth/mcp-oauth-errors.d.ts +5 -0
- package/dist/src/agent/mcp/oauth/mcp-oauth-errors.js +14 -0
- package/dist/src/agent/mcp/oauth/mcp-oauth-manager.d.ts +25 -0
- package/dist/src/agent/mcp/oauth/mcp-oauth-manager.js +219 -0
- package/dist/src/agent/mcp/oauth/mcp-oauth-provider.d.ts +33 -0
- package/dist/src/agent/mcp/oauth/mcp-oauth-provider.js +103 -0
- package/dist/src/agent/mcp/oauth/mcp-oauth-session.d.ts +29 -0
- package/dist/src/agent/mcp/oauth/mcp-oauth-session.js +169 -0
- package/dist/src/agent/mcp/oauth/mcp-oauth-store.d.ts +9 -0
- package/dist/src/agent/mcp/oauth/mcp-oauth-store.js +79 -0
- package/dist/src/agent/mcp/oauth/mcp-oauth-types.d.ts +22 -0
- package/dist/src/agent/mcp/oauth/mcp-oauth-types.js +1 -0
- package/dist/src/agent/memory/builtin-provider.js +23 -4
- package/dist/src/agent/memory/compaction-promotion.d.ts +18 -0
- package/dist/src/agent/memory/compaction-promotion.js +211 -0
- package/dist/src/agent/memory/context/types.d.ts +5 -0
- package/dist/src/agent/memory/manager.d.ts +3 -0
- package/dist/src/agent/memory/manager.js +12 -2
- package/dist/src/agent/memory/trusted-recall.d.ts +7 -0
- package/dist/src/agent/memory/trusted-recall.js +53 -0
- package/dist/src/agent/memory/turn-provenance.d.ts +14 -0
- package/dist/src/agent/memory/turn-provenance.js +60 -0
- package/dist/src/agent/memory/types.d.ts +18 -3
- package/dist/src/agent/memory/user-context-coordinator.js +57 -6
- package/dist/src/agent/skills/marketplace/adapters/store/store-api-client.d.ts +2 -0
- package/dist/src/agent/tools/memory-tool.js +5 -1
- package/dist/src/capabilities/store-connector.js +99 -10
- package/dist/src/cli/commands/channels.js +1 -1
- package/dist/src/cli/commands/connectors.js +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/extension-marketplace.js +1 -1
- package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
- package/dist/src/cli/commands/models.js +1 -1
- package/dist/src/cli/commands/onboard.js +1 -1
- package/dist/src/config/config-mutation.d.ts +14 -0
- package/dist/src/config/config-mutation.js +33 -0
- package/dist/src/config/index.js +3 -3
- package/dist/src/config/paths.d.ts +2 -0
- package/dist/src/config/paths.js +5 -1
- package/dist/src/config/schema.d.ts +17 -0
- package/dist/src/config/schema.js +26 -2
- package/dist/src/connectors/auth-provider-registry.d.ts +1 -1
- package/dist/src/connectors/auth-provider-registry.js +23 -2
- package/dist/src/connectors/install.js +3 -3
- package/dist/src/connectors/instances.d.ts +2 -1
- package/dist/src/connectors/instances.js +15 -5
- package/dist/src/connectors/materialize.d.ts +1 -0
- package/dist/src/connectors/materialize.js +9 -1
- package/dist/src/connectors/runtime-adapter-registry.js +1 -0
- package/dist/src/connectors/types.d.ts +4 -1
- package/dist/src/extensions/connector-dependencies.d.ts +10 -0
- package/dist/src/extensions/connector-dependencies.js +65 -0
- package/dist/src/extensions/install.js +27 -0
- package/dist/src/extensions/normalize-manifest.js +1 -0
- package/dist/src/extensions/sdk/index.js +1 -1
- package/dist/src/extensions/types/manifest.d.ts +2 -0
- package/dist/src/gateway/heartbeat/service.js +1 -1
- package/dist/src/gateway/hono/routes/capabilities.js +8 -8
- package/dist/src/gateway/hono/routes/connectors.js +87 -55
- package/dist/src/gateway/hono/routes/mcp.js +77 -5
- package/dist/src/gateway/hono/routes/voice.js +1 -1
- package/dist/src/gateway/service.js +8 -8
- package/dist/src/heartbeat/index.js +1 -1
- package/dist/src/infra/update-restart.js +1 -1
- package/dist/src/knowledge/connected-knowledge-pipeline.js +26 -4
- package/dist/src/session/store.js +27 -0
- package/dist/src/storage/sqlite/memory-records-repository.d.ts +9 -1
- package/dist/src/storage/sqlite/memory-records-repository.js +40 -6
- package/dist/src/storage/sqlite/migrations/134_memory_provenance.sql +18 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +3 -3
- package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/tui/backends/embedded-backend.js +1 -1
- package/dist/src/user-context/planner.js +8 -3
- package/package.json +2 -2
- package/dist/gateway/static/root/assets/channels-status-swr-DMxB7slL.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-fmda2NEP.js +0 -2
- package/dist/gateway/static/root/assets/settings-advanced-gate-CnYf1R7z.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-BFoEpQ4I.js +0 -1
- package/dist/src/extensions/bundle-mcp.d.ts +0 -18
- package/dist/src/extensions/bundle-mcp.js +0 -69
|
@@ -4,6 +4,7 @@ export declare function materializeConnectorMcpServer(definition: ConnectorDefin
|
|
|
4
4
|
serverId: string;
|
|
5
5
|
server: Record<string, unknown>;
|
|
6
6
|
};
|
|
7
|
+
export declare function connectorDefinitionFromManagedMarker(marker: unknown): ConnectorDefinition | undefined;
|
|
7
8
|
export declare function isManagedConnectorServer(server: unknown): server is Record<string, unknown> & {
|
|
8
9
|
xopcConnector: ManagedConnectorMarker;
|
|
9
10
|
};
|
|
@@ -56,6 +56,7 @@ function materializeConnectorMcpServer(definition, input) {
|
|
|
56
56
|
displayName: definition.displayName,
|
|
57
57
|
source: definition.source,
|
|
58
58
|
artifactSha256: definition.provenance?.sha256,
|
|
59
|
+
definition,
|
|
59
60
|
...input.config && Object.keys(input.config).length > 0 ? { config: input.config } : {}
|
|
60
61
|
};
|
|
61
62
|
const server = {
|
|
@@ -69,10 +70,17 @@ function materializeConnectorMcpServer(definition, input) {
|
|
|
69
70
|
server
|
|
70
71
|
};
|
|
71
72
|
}
|
|
73
|
+
function connectorDefinitionFromManagedMarker(marker) {
|
|
74
|
+
if (!marker || typeof marker !== "object" || Array.isArray(marker)) return void 0;
|
|
75
|
+
const definition = marker.definition;
|
|
76
|
+
if (!definition || typeof definition !== "object" || Array.isArray(definition)) return void 0;
|
|
77
|
+
const record = definition;
|
|
78
|
+
return typeof record.id === "string" && typeof record.version === "string" && record.runtime ? record : void 0;
|
|
79
|
+
}
|
|
72
80
|
function isManagedConnectorServer(server) {
|
|
73
81
|
if (!server || typeof server !== "object" || Array.isArray(server)) return false;
|
|
74
82
|
const marker = server.xopcConnector;
|
|
75
83
|
return Boolean(marker && typeof marker === "object" && !Array.isArray(marker) && marker.managed === true && typeof marker.connectorId === "string");
|
|
76
84
|
}
|
|
77
85
|
//#endregion
|
|
78
|
-
export { assertValidConnectorServerId, isManagedConnectorServer, materializeConnectorMcpServer };
|
|
86
|
+
export { assertValidConnectorServerId, connectorDefinitionFromManagedMarker, isManagedConnectorServer, materializeConnectorMcpServer };
|
|
@@ -32,6 +32,7 @@ function installRecord(config, definition, extra = {}, markerExtra = {}) {
|
|
|
32
32
|
displayName: definition.displayName,
|
|
33
33
|
source: definition.source,
|
|
34
34
|
artifactSha256: definition.provenance?.sha256,
|
|
35
|
+
definition,
|
|
35
36
|
...markerExtra
|
|
36
37
|
},
|
|
37
38
|
runtime: definition.runtime,
|
|
@@ -8,7 +8,8 @@ export type ConnectorAuthDefinition = {
|
|
|
8
8
|
mode: 'apiKey';
|
|
9
9
|
} | {
|
|
10
10
|
mode: 'oauth';
|
|
11
|
-
provider
|
|
11
|
+
provider?: string;
|
|
12
|
+
clientId?: string;
|
|
12
13
|
};
|
|
13
14
|
export type ConnectorScope = 'read' | 'write' | 'admin';
|
|
14
15
|
export type ConnectorVerificationLevel = 'verified' | 'beta' | 'experimental';
|
|
@@ -289,4 +290,6 @@ export type ManagedConnectorMarker = {
|
|
|
289
290
|
config?: Record<string, unknown>;
|
|
290
291
|
source?: ConnectorDefinition['source'];
|
|
291
292
|
artifactSha256?: string;
|
|
293
|
+
/** Immutable install-time snapshot used for update, health, and uninstall after restart. */
|
|
294
|
+
definition?: ConnectorDefinition;
|
|
292
295
|
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Config } from '../config/schema.js';
|
|
2
|
+
export type ExtensionConnectorDiagnostic = {
|
|
3
|
+
extensionId: string;
|
|
4
|
+
connectorId: string;
|
|
5
|
+
message: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function inspectExtensionConnectorDependencies(params: {
|
|
8
|
+
cfg?: Config;
|
|
9
|
+
roots?: string[];
|
|
10
|
+
}): ExtensionConnectorDiagnostic[];
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { init_paths, resolveBundledExtensionsDir, resolveExtensionsDir } from "../config/paths.js";
|
|
2
|
+
import { isRecord } from "../utils/is-record.js";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
5
|
+
//#region src/extensions/connector-dependencies.ts
|
|
6
|
+
init_paths();
|
|
7
|
+
function isExtensionEnabled(extensionId, cfg) {
|
|
8
|
+
const disabled = cfg?.extensions?.disabled;
|
|
9
|
+
if (Array.isArray(disabled) && disabled.includes(extensionId)) return false;
|
|
10
|
+
const enabled = cfg?.extensions?.enabled;
|
|
11
|
+
return !Array.isArray(enabled) || enabled.length === 0 || enabled.includes(extensionId);
|
|
12
|
+
}
|
|
13
|
+
function enabledConnectorIds(cfg) {
|
|
14
|
+
const ids = /* @__PURE__ */ new Set();
|
|
15
|
+
for (const server of Object.values(cfg?.mcp?.servers ?? {})) {
|
|
16
|
+
if (!isRecord(server) || !isRecord(server.xopcConnector)) continue;
|
|
17
|
+
if (server.xopcConnector.managed === true && server.xopcConnector.enabled !== false && typeof server.xopcConnector.connectorId === "string") ids.add(server.xopcConnector.connectorId);
|
|
18
|
+
}
|
|
19
|
+
for (const instance of Object.values(cfg?.connectors?.instances ?? {})) {
|
|
20
|
+
if (!isRecord(instance) || !isRecord(instance.xopcConnector)) continue;
|
|
21
|
+
if (instance.xopcConnector.managed === true && instance.xopcConnector.enabled !== false && typeof instance.xopcConnector.connectorId === "string") ids.add(instance.xopcConnector.connectorId);
|
|
22
|
+
}
|
|
23
|
+
return ids;
|
|
24
|
+
}
|
|
25
|
+
function scanRoot(params) {
|
|
26
|
+
if (!existsSync(params.root)) return;
|
|
27
|
+
for (const entry of readdirSync(params.root, { withFileTypes: true })) {
|
|
28
|
+
if (!entry.isDirectory() || params.seenExtensions.has(entry.name) || !isExtensionEnabled(entry.name, params.cfg)) continue;
|
|
29
|
+
const manifestPath = join(params.root, entry.name, "xopc.extension.json");
|
|
30
|
+
if (!existsSync(manifestPath)) continue;
|
|
31
|
+
params.seenExtensions.add(entry.name);
|
|
32
|
+
let manifest;
|
|
33
|
+
try {
|
|
34
|
+
manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
35
|
+
} catch {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (!isRecord(manifest) || !Array.isArray(manifest.connectorDependencies)) continue;
|
|
39
|
+
const dependencies = [...new Set(manifest.connectorDependencies.filter((value) => typeof value === "string").map((value) => value.trim()).filter(Boolean))];
|
|
40
|
+
for (const connectorId of dependencies) {
|
|
41
|
+
if (params.installed.has(connectorId)) continue;
|
|
42
|
+
params.diagnostics.push({
|
|
43
|
+
extensionId: entry.name,
|
|
44
|
+
connectorId,
|
|
45
|
+
message: `Extension "${entry.name}" requires enabled Connector "${connectorId}". Install and connect it from the Connector Store.`
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function inspectExtensionConnectorDependencies(params) {
|
|
51
|
+
const diagnostics = [];
|
|
52
|
+
const installed = enabledConnectorIds(params.cfg);
|
|
53
|
+
const seenExtensions = /* @__PURE__ */ new Set();
|
|
54
|
+
const roots = params.roots ?? [resolveExtensionsDir(), resolveBundledExtensionsDir()].filter((root) => Boolean(root));
|
|
55
|
+
for (const root of roots) scanRoot({
|
|
56
|
+
root,
|
|
57
|
+
cfg: params.cfg,
|
|
58
|
+
installed,
|
|
59
|
+
seenExtensions,
|
|
60
|
+
diagnostics
|
|
61
|
+
});
|
|
62
|
+
return diagnostics;
|
|
63
|
+
}
|
|
64
|
+
//#endregion
|
|
65
|
+
export { inspectExtensionConnectorDependencies };
|
|
@@ -172,6 +172,24 @@ function isSafeZipPath(name) {
|
|
|
172
172
|
for (const p of normalized.split("/")) if (p === "..") return false;
|
|
173
173
|
return true;
|
|
174
174
|
}
|
|
175
|
+
function findEmbeddedMcpConfig(root) {
|
|
176
|
+
for (const entry of readdirSync(root, { withFileTypes: true })) {
|
|
177
|
+
if (entry.isSymbolicLink()) continue;
|
|
178
|
+
const path = join(root, entry.name);
|
|
179
|
+
if (entry.isFile() && entry.name.toLowerCase() === ".mcp.json") return path;
|
|
180
|
+
if (entry.isDirectory()) {
|
|
181
|
+
const nested = findEmbeddedMcpConfig(path);
|
|
182
|
+
if (nested) return nested;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function validateConnectorDependencies(value) {
|
|
187
|
+
if (value === void 0) return void 0;
|
|
188
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) return "Extension connectorDependencies must be an array of unique Connector ids";
|
|
189
|
+
const dependencies = value;
|
|
190
|
+
const validId = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/;
|
|
191
|
+
if (dependencies.some((id) => !validId.test(id)) || new Set(dependencies).size !== dependencies.length) return "Extension connectorDependencies must be an array of unique Connector ids";
|
|
192
|
+
}
|
|
175
193
|
function isIgnorableZipEntry(name) {
|
|
176
194
|
const n = name.replace(/\\/g, "/");
|
|
177
195
|
if (n.startsWith("__MACOSX/")) return true;
|
|
@@ -448,6 +466,15 @@ async function installFromDirectory(sourceDir, extensionsDir) {
|
|
|
448
466
|
ok: false,
|
|
449
467
|
error: "Extension must include xopc.extension.json"
|
|
450
468
|
};
|
|
469
|
+
if (findEmbeddedMcpConfig(sourceDir)) return {
|
|
470
|
+
ok: false,
|
|
471
|
+
error: "Extensions must declare connectorDependencies instead of embedding .mcp.json"
|
|
472
|
+
};
|
|
473
|
+
const connectorDependencyError = validateConnectorDependencies(manifest.connectorDependencies);
|
|
474
|
+
if (connectorDependencyError) return {
|
|
475
|
+
ok: false,
|
|
476
|
+
error: connectorDependencyError
|
|
477
|
+
};
|
|
451
478
|
if (!manifest.engines?.xopc) return {
|
|
452
479
|
ok: false,
|
|
453
480
|
error: "Extension manifest must declare engines.xopc"
|
|
@@ -130,6 +130,7 @@ function normalizeExtensionManifest(raw) {
|
|
|
130
130
|
main: typeof raw.main === "string" ? raw.main : void 0,
|
|
131
131
|
configSchema: isRecord(raw.configSchema) ? raw.configSchema : void 0,
|
|
132
132
|
dependencies: isRecord(raw.dependencies) ? raw.dependencies : void 0,
|
|
133
|
+
connectorDependencies: Array.isArray(raw.connectorDependencies) ? [...new Set(raw.connectorDependencies.filter((value) => typeof value === "string").map((value) => value.trim()).filter(Boolean))] : void 0,
|
|
133
134
|
enabledByDefault: typeof raw.enabledByDefault === "boolean" ? raw.enabledByDefault : void 0,
|
|
134
135
|
providers: Array.isArray(raw.providers) ? raw.providers.filter((x) => typeof x === "string") : void 0,
|
|
135
136
|
speechProviders: Array.isArray(raw.speechProviders) ? raw.speechProviders.filter((x) => typeof x === "string") : void 0,
|
|
@@ -7,8 +7,8 @@ import { SlotRegistry, getSlotRegistry, registerSlotType } from "../slots.js";
|
|
|
7
7
|
import { ExtensionDiagnostics, ExtensionLoaderCacheImpl, getExtensionCache, getExtensionDiagnostics } from "../diagnostics.js";
|
|
8
8
|
import "../loader.js";
|
|
9
9
|
import { ExtensionHookRunner, createHookContext, isHookEvent } from "../hooks.js";
|
|
10
|
-
import { registerExtensionCliProgram } from "./channel-helpers.js";
|
|
11
10
|
import { defineChannelPluginEntry } from "./channel-entry.js";
|
|
11
|
+
import { registerExtensionCliProgram } from "./channel-helpers.js";
|
|
12
12
|
import { lazyFunction, lazyModule } from "./lazy.js";
|
|
13
13
|
import { createMockExtensionApi, createTestGateway } from "./testing.js";
|
|
14
14
|
//#region src/extensions/sdk/index.ts
|
|
@@ -20,6 +20,8 @@ export interface ExtensionManifest {
|
|
|
20
20
|
main?: string;
|
|
21
21
|
configSchema?: Record<string, unknown>;
|
|
22
22
|
dependencies?: Record<string, string>;
|
|
23
|
+
/** Connector ids that must already be installed and enabled. Extensions never embed MCP server configuration. */
|
|
24
|
+
connectorDependencies?: string[];
|
|
23
25
|
enabledByDefault?: boolean;
|
|
24
26
|
providers?: string[];
|
|
25
27
|
/** Speech/TTS provider ids implemented by this extension. */
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { createLogger } from "../../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
3
|
import { shouldSilence, stripHeartbeatToken } from "../../heartbeat/tokens.js";
|
|
4
|
+
import { appendCronEventLines } from "../../heartbeat/event-prompt.js";
|
|
4
5
|
import { isWithinActiveHours } from "../../heartbeat/active-hours.js";
|
|
5
6
|
import { isHeartbeatContentEmpty } from "../../heartbeat/content-check.js";
|
|
6
|
-
import { appendCronEventLines } from "../../heartbeat/event-prompt.js";
|
|
7
7
|
import { createHeartbeatWake } from "../../heartbeat/wake.js";
|
|
8
8
|
import { resolveHeartbeatMdPath } from "../workspace-heartbeat-path.js";
|
|
9
9
|
import { readFile } from "fs/promises";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getStoreConnectorInstallPlan, installStoreConnector, listStoreConnectors } from "../../../capabilities/store-connector.js";
|
|
2
|
+
import { ConfigPersistenceError, persistConfigMutation } from "../../../config/config-mutation.js";
|
|
2
3
|
//#region src/gateway/hono/routes/capabilities.ts
|
|
3
4
|
function errorMessage(error) {
|
|
4
5
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -50,14 +51,13 @@ function registerCapabilityRoutes(authenticated, deps) {
|
|
|
50
51
|
authenticated.post("/api/capabilities/connectors/:name/install", strictRateLimitMiddleware, async (c) => {
|
|
51
52
|
const body = await c.req.json().catch(() => ({}));
|
|
52
53
|
const input = body && typeof body === "object" && !Array.isArray(body) ? body : {};
|
|
54
|
+
const config = service.currentConfig;
|
|
53
55
|
try {
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
error: saved.error ?? "Failed to save connector configuration."
|
|
60
|
-
}, 500);
|
|
56
|
+
const { instance, plan } = await persistConfigMutation({
|
|
57
|
+
config,
|
|
58
|
+
mutate: () => installStoreConnector(config, c.req.param("name"), input, optionalVersion(body)),
|
|
59
|
+
save: () => service.saveConfig(config)
|
|
60
|
+
});
|
|
61
61
|
return c.json({
|
|
62
62
|
ok: true,
|
|
63
63
|
payload: {
|
|
@@ -69,7 +69,7 @@ function registerCapabilityRoutes(authenticated, deps) {
|
|
|
69
69
|
return c.json({
|
|
70
70
|
ok: false,
|
|
71
71
|
error: errorMessage(error)
|
|
72
|
-
}, 400);
|
|
72
|
+
}, error instanceof ConfigPersistenceError ? 500 : 400);
|
|
73
73
|
}
|
|
74
74
|
});
|
|
75
75
|
}
|
|
@@ -13,8 +13,9 @@ import { listConnectorProviders } from "../../../connectors/providers.js";
|
|
|
13
13
|
import { getConnectorDefinition, listConnectorCatalog } from "../../../connectors/catalog.js";
|
|
14
14
|
import { listUnderstandingSourceGrants, revokeUnderstandingSourceGrant } from "../../../user-context/sources/repository.js";
|
|
15
15
|
import { recordConnectorHealthUsage } from "../../../connectors/usage.js";
|
|
16
|
-
import { getConnectorInstance, listConnectorInstances } from "../../../connectors/instances.js";
|
|
16
|
+
import { getConnectorInstance, getInstalledConnectorDefinition, listConnectorInstances } from "../../../connectors/instances.js";
|
|
17
17
|
import { installConnector, installConnectorDefinition, uninstallConnector, updateConnectorConfig } from "../../../connectors/install.js";
|
|
18
|
+
import { getMcpOAuthManager } from "../../../agent/mcp/oauth/mcp-oauth-manager.js";
|
|
18
19
|
import { startConnectorAuthorization } from "../../../connectors/auth-provider-registry.js";
|
|
19
20
|
import { composioLogoResponse } from "../../../connectors/composio-logo.js";
|
|
20
21
|
import { inspectManagedComposioStatus } from "../../../connectors/composio-managed-client.js";
|
|
@@ -25,6 +26,7 @@ import { ingestLocalFolderSource } from "../../../connectors/connected-source-in
|
|
|
25
26
|
import { previewConnectorDefinition, testConnectorInstance } from "../../../connectors/health.js";
|
|
26
27
|
import { setConnectorEnabled } from "../../../connectors/lifecycle.js";
|
|
27
28
|
import { projectComposioConnectionStatus } from "../../../connectors/runtime-status.js";
|
|
29
|
+
import { ConfigPersistenceError, persistConfigMutation } from "../../../config/config-mutation.js";
|
|
28
30
|
//#region src/gateway/hono/routes/connectors.ts
|
|
29
31
|
init_agent_scope();
|
|
30
32
|
function errorMessage(error) {
|
|
@@ -48,9 +50,39 @@ function registerConnectorRoutes(authenticated, deps) {
|
|
|
48
50
|
}
|
|
49
51
|
});
|
|
50
52
|
});
|
|
51
|
-
authenticated.get("/api/connectors/installed", (c) => {
|
|
53
|
+
authenticated.get("/api/connectors/installed", async (c) => {
|
|
52
54
|
const config = service.currentConfig;
|
|
53
|
-
const instances = listConnectorInstances(config)
|
|
55
|
+
const instances = await Promise.all(listConnectorInstances(config).map(async (instance) => {
|
|
56
|
+
if (!instance.enabled || instance.materialized.type !== "mcp") return instance;
|
|
57
|
+
const server = config.mcp?.servers?.[instance.materialized.serverId];
|
|
58
|
+
if (!server) return instance;
|
|
59
|
+
const oauth = await getMcpOAuthManager().status(instance.materialized.serverId, server);
|
|
60
|
+
if (!oauth.configured) return instance;
|
|
61
|
+
if (oauth.status === "connected") return {
|
|
62
|
+
...instance,
|
|
63
|
+
authStatus: "connected",
|
|
64
|
+
connectionStatus: "connected"
|
|
65
|
+
};
|
|
66
|
+
if (oauth.status === "authorizing") return {
|
|
67
|
+
...instance,
|
|
68
|
+
status: "connecting",
|
|
69
|
+
authStatus: "unknown",
|
|
70
|
+
connectionStatus: "connecting"
|
|
71
|
+
};
|
|
72
|
+
if (oauth.status === "error") return {
|
|
73
|
+
...instance,
|
|
74
|
+
status: "failed",
|
|
75
|
+
authStatus: "unauthorized",
|
|
76
|
+
connectionStatus: "error",
|
|
77
|
+
lastError: oauth.session?.error ?? instance.lastError
|
|
78
|
+
};
|
|
79
|
+
return {
|
|
80
|
+
...instance,
|
|
81
|
+
status: "unauthorized",
|
|
82
|
+
authStatus: "missing",
|
|
83
|
+
connectionStatus: "disconnected"
|
|
84
|
+
};
|
|
85
|
+
}));
|
|
54
86
|
const connections = listConnectorConnections({ principalId: "local-owner" });
|
|
55
87
|
return c.json({
|
|
56
88
|
ok: true,
|
|
@@ -348,12 +380,11 @@ function registerConnectorRoutes(authenticated, deps) {
|
|
|
348
380
|
}, 400);
|
|
349
381
|
const config = service.currentConfig;
|
|
350
382
|
try {
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
}, 500);
|
|
383
|
+
await persistConfigMutation({
|
|
384
|
+
config,
|
|
385
|
+
mutate: () => setComposioToolkitScope(config, toolkit, scope),
|
|
386
|
+
save: () => service.saveConfig(config)
|
|
387
|
+
});
|
|
357
388
|
return c.json({
|
|
358
389
|
ok: true,
|
|
359
390
|
payload: {
|
|
@@ -365,7 +396,7 @@ function registerConnectorRoutes(authenticated, deps) {
|
|
|
365
396
|
return c.json({
|
|
366
397
|
ok: false,
|
|
367
398
|
error: errorMessage(error)
|
|
368
|
-
}, 400);
|
|
399
|
+
}, error instanceof ConfigPersistenceError ? 500 : 400);
|
|
369
400
|
}
|
|
370
401
|
});
|
|
371
402
|
authenticated.post("/api/connectors/composio/tools/:slug/execute", strictRateLimitMiddleware, async (c) => {
|
|
@@ -573,14 +604,16 @@ function registerConnectorRoutes(authenticated, deps) {
|
|
|
573
604
|
});
|
|
574
605
|
});
|
|
575
606
|
authenticated.post("/api/connectors/:id/auth/start", strictRateLimitMiddleware, async (c) => {
|
|
576
|
-
const
|
|
577
|
-
const
|
|
607
|
+
const connectorOrInstanceId = c.req.param("id");
|
|
608
|
+
const config = service.currentConfig;
|
|
609
|
+
const instance = getConnectorInstance(config, connectorOrInstanceId);
|
|
610
|
+
const connector = instance ? getInstalledConnectorDefinition(config, instance.instanceId) : getConnectorDefinition(connectorOrInstanceId);
|
|
578
611
|
if (!connector) return c.json({
|
|
579
612
|
ok: false,
|
|
580
|
-
error: `Unknown connector: ${
|
|
613
|
+
error: `Unknown connector: ${connectorOrInstanceId}`
|
|
581
614
|
}, 404);
|
|
582
615
|
try {
|
|
583
|
-
const authorization = await startConnectorAuthorization(connector,
|
|
616
|
+
const authorization = await startConnectorAuthorization(connector, config, instance?.instanceId);
|
|
584
617
|
return c.json({
|
|
585
618
|
ok: true,
|
|
586
619
|
payload: { authorization }
|
|
@@ -628,12 +661,11 @@ function registerConnectorRoutes(authenticated, deps) {
|
|
|
628
661
|
const registryDefinition = body && typeof body === "object" && !Array.isArray(body) && body.definition && typeof body.definition === "object" && !Array.isArray(body.definition) ? body.definition : void 0;
|
|
629
662
|
const config = service.currentConfig;
|
|
630
663
|
try {
|
|
631
|
-
const instance =
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
}, 500);
|
|
664
|
+
const instance = await persistConfigMutation({
|
|
665
|
+
config,
|
|
666
|
+
mutate: () => registryDefinition?.id === connectorId ? installConnectorDefinition(config, registryDefinition, input) : installConnector(config, connectorId, input),
|
|
667
|
+
save: () => service.saveConfig(config)
|
|
668
|
+
});
|
|
637
669
|
return c.json({
|
|
638
670
|
ok: true,
|
|
639
671
|
payload: { instance }
|
|
@@ -642,7 +674,7 @@ function registerConnectorRoutes(authenticated, deps) {
|
|
|
642
674
|
return c.json({
|
|
643
675
|
ok: false,
|
|
644
676
|
error: errorMessage(error)
|
|
645
|
-
}, 400);
|
|
677
|
+
}, error instanceof ConfigPersistenceError ? 500 : 400);
|
|
646
678
|
}
|
|
647
679
|
});
|
|
648
680
|
authenticated.post("/api/connectors/:id/test", async (c) => {
|
|
@@ -659,12 +691,11 @@ function registerConnectorRoutes(authenticated, deps) {
|
|
|
659
691
|
}, 400);
|
|
660
692
|
try {
|
|
661
693
|
const result = await testConnectorInstance(config, instance.materialized.serverId);
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
}, 500);
|
|
694
|
+
await persistConfigMutation({
|
|
695
|
+
config,
|
|
696
|
+
mutate: () => recordConnectorHealthUsage(config, instance.instanceId, result),
|
|
697
|
+
save: () => service.saveConfig(config)
|
|
698
|
+
});
|
|
668
699
|
return c.json({
|
|
669
700
|
ok: true,
|
|
670
701
|
payload: result
|
|
@@ -701,12 +732,11 @@ function registerConnectorRoutes(authenticated, deps) {
|
|
|
701
732
|
const input = body && typeof body === "object" && !Array.isArray(body) ? body : {};
|
|
702
733
|
const config = service.currentConfig;
|
|
703
734
|
try {
|
|
704
|
-
const instance =
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
}, 500);
|
|
735
|
+
const instance = await persistConfigMutation({
|
|
736
|
+
config,
|
|
737
|
+
mutate: () => updateConnectorConfig(config, instanceId, input),
|
|
738
|
+
save: () => service.saveConfig(config)
|
|
739
|
+
});
|
|
710
740
|
return c.json({
|
|
711
741
|
ok: true,
|
|
712
742
|
payload: { instance }
|
|
@@ -715,19 +745,18 @@ function registerConnectorRoutes(authenticated, deps) {
|
|
|
715
745
|
return c.json({
|
|
716
746
|
ok: false,
|
|
717
747
|
error: errorMessage(error)
|
|
718
|
-
}, 400);
|
|
748
|
+
}, error instanceof ConfigPersistenceError ? 500 : 400);
|
|
719
749
|
}
|
|
720
750
|
});
|
|
721
751
|
authenticated.post("/api/connectors/:id/enable", strictRateLimitMiddleware, async (c) => {
|
|
722
752
|
const instanceId = c.req.param("id");
|
|
723
753
|
const config = service.currentConfig;
|
|
724
754
|
try {
|
|
725
|
-
const instance =
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
}, 500);
|
|
755
|
+
const instance = await persistConfigMutation({
|
|
756
|
+
config,
|
|
757
|
+
mutate: () => setConnectorEnabled(config, instanceId, true),
|
|
758
|
+
save: () => service.saveConfig(config)
|
|
759
|
+
});
|
|
731
760
|
return c.json({
|
|
732
761
|
ok: true,
|
|
733
762
|
payload: { instance }
|
|
@@ -736,19 +765,18 @@ function registerConnectorRoutes(authenticated, deps) {
|
|
|
736
765
|
return c.json({
|
|
737
766
|
ok: false,
|
|
738
767
|
error: errorMessage(error)
|
|
739
|
-
}, 400);
|
|
768
|
+
}, error instanceof ConfigPersistenceError ? 500 : 400);
|
|
740
769
|
}
|
|
741
770
|
});
|
|
742
771
|
authenticated.post("/api/connectors/:id/disable", strictRateLimitMiddleware, async (c) => {
|
|
743
772
|
const instanceId = c.req.param("id");
|
|
744
773
|
const config = service.currentConfig;
|
|
745
774
|
try {
|
|
746
|
-
const instance =
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
}, 500);
|
|
775
|
+
const instance = await persistConfigMutation({
|
|
776
|
+
config,
|
|
777
|
+
mutate: () => setConnectorEnabled(config, instanceId, false),
|
|
778
|
+
save: () => service.saveConfig(config)
|
|
779
|
+
});
|
|
752
780
|
return c.json({
|
|
753
781
|
ok: true,
|
|
754
782
|
payload: { instance }
|
|
@@ -757,19 +785,23 @@ function registerConnectorRoutes(authenticated, deps) {
|
|
|
757
785
|
return c.json({
|
|
758
786
|
ok: false,
|
|
759
787
|
error: errorMessage(error)
|
|
760
|
-
}, 400);
|
|
788
|
+
}, error instanceof ConfigPersistenceError ? 500 : 400);
|
|
761
789
|
}
|
|
762
790
|
});
|
|
763
791
|
authenticated.delete("/api/connectors/:id", strictRateLimitMiddleware, async (c) => {
|
|
764
792
|
const instanceId = c.req.param("id");
|
|
765
793
|
const config = service.currentConfig;
|
|
766
794
|
try {
|
|
767
|
-
const
|
|
768
|
-
const
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
795
|
+
const definition = getInstalledConnectorDefinition(config, instanceId);
|
|
796
|
+
const installed = getConnectorInstance(config, instanceId);
|
|
797
|
+
const serverId = installed?.materialized.type === "mcp" ? installed.materialized.serverId : void 0;
|
|
798
|
+
const rawServer = serverId ? config.mcp?.servers?.[serverId] : void 0;
|
|
799
|
+
if (definition?.auth.mode === "oauth" && definition.runtime.type === "mcp" && rawServer) await getMcpOAuthManager().disconnect(serverId, rawServer);
|
|
800
|
+
const instance = await persistConfigMutation({
|
|
801
|
+
config,
|
|
802
|
+
mutate: () => uninstallConnector(config, instanceId),
|
|
803
|
+
save: () => service.saveConfig(config)
|
|
804
|
+
});
|
|
773
805
|
return c.json({
|
|
774
806
|
ok: true,
|
|
775
807
|
payload: { instance }
|
|
@@ -778,7 +810,7 @@ function registerConnectorRoutes(authenticated, deps) {
|
|
|
778
810
|
return c.json({
|
|
779
811
|
ok: false,
|
|
780
812
|
error: errorMessage(error)
|
|
781
|
-
}, 400);
|
|
813
|
+
}, error instanceof ConfigPersistenceError ? 500 : 400);
|
|
782
814
|
}
|
|
783
815
|
});
|
|
784
816
|
}
|
|
@@ -2,21 +2,31 @@ import { canonicalizeConfiguredMcpServer, normalizeConfiguredMcpServers } from "
|
|
|
2
2
|
import { loadMergedBundleMcpConfig } from "../../../agent/mcp/bundle-mcp-config.js";
|
|
3
3
|
import { isManagedConnectorServer } from "../../../connectors/materialize.js";
|
|
4
4
|
import { getWorkspacePath } from "../../../config/workspace-path-helpers.js";
|
|
5
|
+
import { getMcpOAuthManager } from "../../../agent/mcp/oauth/mcp-oauth-manager.js";
|
|
5
6
|
import { listBundleMcpServerCapabilitiesForGateway, listBundleMcpServerToolsForGateway } from "../../../agent/mcp/bundle-mcp-gateway.js";
|
|
6
7
|
//#region src/gateway/hono/routes/mcp.ts
|
|
7
8
|
function registerMcpRoutes(authenticated, deps) {
|
|
8
|
-
|
|
9
|
+
const resolveServer = (id) => {
|
|
10
|
+
const cfg = deps.service.currentConfig;
|
|
11
|
+
return loadMergedBundleMcpConfig({
|
|
12
|
+
workspaceDir: getWorkspacePath(cfg) || "./workspace",
|
|
13
|
+
cfg
|
|
14
|
+
}).config.mcpServers[id];
|
|
15
|
+
};
|
|
16
|
+
authenticated.get("/api/mcp/servers", async (c) => {
|
|
9
17
|
const cfg = deps.service.currentConfig;
|
|
10
18
|
const merged = loadMergedBundleMcpConfig({
|
|
11
19
|
workspaceDir: getWorkspacePath(cfg) || "./workspace",
|
|
12
20
|
cfg
|
|
13
21
|
});
|
|
14
22
|
const configured = normalizeConfiguredMcpServers(cfg.mcp?.servers);
|
|
15
|
-
const
|
|
23
|
+
const oauthManager = getMcpOAuthManager();
|
|
24
|
+
const servers = await Promise.all(Object.entries(configured).map(async ([id, server]) => ({
|
|
16
25
|
id,
|
|
17
26
|
managed: isManagedConnectorServer(server),
|
|
18
|
-
connectorId: isManagedConnectorServer(server) ? server.xopcConnector.connectorId : void 0
|
|
19
|
-
|
|
27
|
+
connectorId: isManagedConnectorServer(server) ? server.xopcConnector.connectorId : void 0,
|
|
28
|
+
oauth: await oauthManager.status(id, server)
|
|
29
|
+
})));
|
|
20
30
|
return c.json({
|
|
21
31
|
ok: true,
|
|
22
32
|
payload: {
|
|
@@ -26,6 +36,62 @@ function registerMcpRoutes(authenticated, deps) {
|
|
|
26
36
|
}
|
|
27
37
|
});
|
|
28
38
|
});
|
|
39
|
+
authenticated.get("/api/mcp/servers/:id/oauth", async (c) => {
|
|
40
|
+
const id = c.req.param("id");
|
|
41
|
+
const server = resolveServer(id);
|
|
42
|
+
if (!server) return c.json({
|
|
43
|
+
ok: false,
|
|
44
|
+
error: `Unknown MCP server: ${id}`
|
|
45
|
+
}, 404);
|
|
46
|
+
return c.json({
|
|
47
|
+
ok: true,
|
|
48
|
+
payload: await getMcpOAuthManager().status(id, server)
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
authenticated.post("/api/mcp/servers/:id/oauth/start", deps.strictRateLimitMiddleware, async (c) => {
|
|
52
|
+
const id = c.req.param("id");
|
|
53
|
+
const server = resolveServer(id);
|
|
54
|
+
if (!server) return c.json({
|
|
55
|
+
ok: false,
|
|
56
|
+
error: `Unknown MCP server: ${id}`
|
|
57
|
+
}, 404);
|
|
58
|
+
try {
|
|
59
|
+
const payload = await getMcpOAuthManager().start({
|
|
60
|
+
serverId: id,
|
|
61
|
+
rawServer: server,
|
|
62
|
+
cfg: deps.service.currentConfig
|
|
63
|
+
});
|
|
64
|
+
return c.json({
|
|
65
|
+
ok: true,
|
|
66
|
+
payload
|
|
67
|
+
});
|
|
68
|
+
} catch (err) {
|
|
69
|
+
return c.json({
|
|
70
|
+
ok: false,
|
|
71
|
+
error: err instanceof Error ? err.message : String(err)
|
|
72
|
+
}, 400);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
authenticated.delete("/api/mcp/servers/:id/oauth", deps.strictRateLimitMiddleware, async (c) => {
|
|
76
|
+
const id = c.req.param("id");
|
|
77
|
+
const server = resolveServer(id);
|
|
78
|
+
if (!server) return c.json({
|
|
79
|
+
ok: false,
|
|
80
|
+
error: `Unknown MCP server: ${id}`
|
|
81
|
+
}, 404);
|
|
82
|
+
try {
|
|
83
|
+
const payload = await getMcpOAuthManager().disconnect(id, server);
|
|
84
|
+
return c.json({
|
|
85
|
+
ok: true,
|
|
86
|
+
payload
|
|
87
|
+
});
|
|
88
|
+
} catch (err) {
|
|
89
|
+
return c.json({
|
|
90
|
+
ok: false,
|
|
91
|
+
error: err instanceof Error ? err.message : String(err)
|
|
92
|
+
}, 400);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
29
95
|
authenticated.get("/api/mcp/servers/:id/tools", async (c) => {
|
|
30
96
|
const id = c.req.param("id");
|
|
31
97
|
const cfg = deps.service.currentConfig;
|
|
@@ -79,11 +145,17 @@ function registerMcpRoutes(authenticated, deps) {
|
|
|
79
145
|
workspaceDir,
|
|
80
146
|
cfg
|
|
81
147
|
}).config.mcpServers;
|
|
82
|
-
|
|
148
|
+
const knownServer = inlineServer ?? servers[id] ?? mergedServers[id];
|
|
149
|
+
if (!knownServer) return c.json({
|
|
83
150
|
ok: false,
|
|
84
151
|
error: `Unknown MCP server: ${id}`
|
|
85
152
|
}, 404);
|
|
86
153
|
try {
|
|
154
|
+
const oauth = await getMcpOAuthManager().status(id, knownServer);
|
|
155
|
+
if (oauth.configured && oauth.status !== "connected") return c.json({
|
|
156
|
+
ok: false,
|
|
157
|
+
error: oauth.session?.error ?? "MCP server authorization is required"
|
|
158
|
+
}, 409);
|
|
87
159
|
const capabilities = await listBundleMcpServerCapabilitiesForGateway({
|
|
88
160
|
workspaceDir,
|
|
89
161
|
cfg: inlineServer ? {
|
|
@@ -14,8 +14,8 @@ import "../../../voice/stt/index.js";
|
|
|
14
14
|
import { listSttProvidersForApi } from "../../../voice/stt/list-providers.js";
|
|
15
15
|
import "../../../voice/tts/index.js";
|
|
16
16
|
import { createGatewayRouteLogger } from "../lib/route-logger.js";
|
|
17
|
-
import { listLocalVoiceModelStatuses, removeLocalVoiceModel, startLocalVoiceModelInstall } from "../../../voice/local/model-manager.js";
|
|
18
17
|
import { listTtsProvidersForApi } from "../../../voice/tts/list-providers.js";
|
|
18
|
+
import { listLocalVoiceModelStatuses, removeLocalVoiceModel, startLocalVoiceModelInstall } from "../../../voice/local/model-manager.js";
|
|
19
19
|
//#region src/gateway/hono/routes/voice.ts
|
|
20
20
|
init_providers();
|
|
21
21
|
const log = createGatewayRouteLogger("Voice");
|