@opengeni/core 0.20.13 → 0.20.16
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/domain/capabilities.d.ts +10 -5
- package/dist/index.js +45 -18
- package/dist/index.js.map +1 -1
- package/package.json +10 -10
- package/src/domain/capabilities.ts +72 -20
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/core",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.16",
|
|
4
4
|
"description": "OpenGeni framework-agnostic core: the domain, access, and billing layers (neutral access, off-HTTP V2 surface). Behavior-preserving extraction from apps/api — keeps Hono's HTTPException for error throwing (typed-errors cleanup deferred).",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -34,15 +34,15 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
37
|
-
"@opengeni/codex": "^0.2.
|
|
38
|
-
"@opengeni/config": "^0.10.
|
|
39
|
-
"@opengeni/contracts": "^0.38.
|
|
40
|
-
"@opengeni/db": "^0.27.
|
|
41
|
-
"@opengeni/documents": "^0.5.
|
|
42
|
-
"@opengeni/events": "^0.3.
|
|
43
|
-
"@opengeni/observability": "^0.4.
|
|
44
|
-
"@opengeni/runtime": "^0.18.
|
|
45
|
-
"@opengeni/storage": "^0.2.
|
|
37
|
+
"@opengeni/codex": "^0.2.11",
|
|
38
|
+
"@opengeni/config": "^0.10.14",
|
|
39
|
+
"@opengeni/contracts": "^0.38.3",
|
|
40
|
+
"@opengeni/db": "^0.27.11",
|
|
41
|
+
"@opengeni/documents": "^0.5.7",
|
|
42
|
+
"@opengeni/events": "^0.3.77",
|
|
43
|
+
"@opengeni/observability": "^0.4.16",
|
|
44
|
+
"@opengeni/runtime": "^0.18.15",
|
|
45
|
+
"@opengeni/storage": "^0.2.67",
|
|
46
46
|
"hono": "^4.12.18"
|
|
47
47
|
},
|
|
48
48
|
"engines": {
|
|
@@ -29,6 +29,8 @@ import {
|
|
|
29
29
|
getCapabilityCatalogItem,
|
|
30
30
|
getCapabilityInstallation,
|
|
31
31
|
getConnectionMetadata,
|
|
32
|
+
getCodexAppsCredentialAuthorizationForRun,
|
|
33
|
+
getWorkspaceGrant,
|
|
32
34
|
getPackInstallation,
|
|
33
35
|
getStoredCapabilityHeaderCiphertext,
|
|
34
36
|
getVariableSet,
|
|
@@ -45,6 +47,7 @@ import {
|
|
|
45
47
|
type EnabledMcpCapabilityServer,
|
|
46
48
|
} from "@opengeni/db";
|
|
47
49
|
import { HTTPException } from "hono/http-exception";
|
|
50
|
+
import { hasPermission } from "../access";
|
|
48
51
|
import {
|
|
49
52
|
getSkillLibraryEntry,
|
|
50
53
|
listSkillLibraryEntries,
|
|
@@ -137,6 +140,15 @@ export async function createCatalogItem(input: {
|
|
|
137
140
|
message: "skill ids are managed by the OpenGeni skill library or runtime adapters",
|
|
138
141
|
});
|
|
139
142
|
}
|
|
143
|
+
if (
|
|
144
|
+
input.payload.kind === "mcp" &&
|
|
145
|
+
typeof input.payload.metadata.mcpServerId === "string" &&
|
|
146
|
+
input.payload.metadata.mcpServerId.trim() === CODEX_APPS_MCP_SERVER_ID
|
|
147
|
+
) {
|
|
148
|
+
throw new HTTPException(422, {
|
|
149
|
+
message: `${CODEX_APPS_MCP_SERVER_ID} is reserved for the canonical Codex Apps service`,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
140
152
|
const source =
|
|
141
153
|
input.payload.source === "built_in" ||
|
|
142
154
|
input.payload.source === "library" ||
|
|
@@ -721,36 +733,76 @@ export async function settingsWithEnabledCapabilityMcpServers(
|
|
|
721
733
|
workspaceId: string,
|
|
722
734
|
settings: Settings,
|
|
723
735
|
): Promise<Settings> {
|
|
724
|
-
const enabled = await
|
|
725
|
-
|
|
736
|
+
const [enabled, codexAppsCredentialId] = await Promise.all([
|
|
737
|
+
listEnabledMcpCapabilityServers(db, workspaceId),
|
|
738
|
+
resolveCodexAppsCredentialIdForRun(db, workspaceId),
|
|
739
|
+
]);
|
|
740
|
+
return settingsWithCodexAppsMcpServer(
|
|
741
|
+
settingsWithMcpCapabilityServers(settings, enabled),
|
|
742
|
+
codexAppsCredentialId !== null,
|
|
743
|
+
);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
* Resolve executable Apps authority. The connector must remain active and its
|
|
748
|
+
* exact owner must still hold workspace connection-management permission.
|
|
749
|
+
*/
|
|
750
|
+
export async function resolveCodexAppsCredentialIdForRun(
|
|
751
|
+
db: Database,
|
|
752
|
+
workspaceId: string,
|
|
753
|
+
): Promise<string | null> {
|
|
754
|
+
const authorization = await getCodexAppsCredentialAuthorizationForRun(db, workspaceId);
|
|
755
|
+
if (!authorization) return null;
|
|
756
|
+
const grant = await getWorkspaceGrant(db, authorization.ownerSubjectId, workspaceId);
|
|
757
|
+
return grant && hasPermission(grant.permissions, "connections:write")
|
|
758
|
+
? authorization.credentialId
|
|
759
|
+
: null;
|
|
726
760
|
}
|
|
727
761
|
|
|
728
762
|
/**
|
|
729
|
-
* Register Codex Apps as an optional runtime MCP when the deployment
|
|
730
|
-
*
|
|
731
|
-
*
|
|
732
|
-
*
|
|
763
|
+
* Register Codex Apps as an optional runtime MCP only when the deployment is
|
|
764
|
+
* enabled and this workspace has an active explicit Apps designation.
|
|
765
|
+
* Registration only makes the server selectable; session policy decides
|
|
766
|
+
* whether the model sees it.
|
|
733
767
|
*/
|
|
734
|
-
export function settingsWithCodexAppsMcpServer(
|
|
768
|
+
export function settingsWithCodexAppsMcpServer(
|
|
769
|
+
settings: Settings,
|
|
770
|
+
credentialAvailable: boolean,
|
|
771
|
+
): Settings {
|
|
772
|
+
const canonicalServer = {
|
|
773
|
+
id: CODEX_APPS_MCP_SERVER_ID,
|
|
774
|
+
name: CODEX_APPS_MCP_SERVER_NAME,
|
|
775
|
+
url: CODEX_APPS_MCP_URL,
|
|
776
|
+
timeoutMs: CODEX_APPS_STARTUP_TIMEOUT_MS,
|
|
777
|
+
// Availability is credential-specific, so discover on every run.
|
|
778
|
+
cacheToolsList: false,
|
|
779
|
+
};
|
|
780
|
+
// The id is a credential-routing trust boundary. Discard every configured or
|
|
781
|
+
// capability-provided claimant before optionally appending the one canonical
|
|
782
|
+
// endpoint; preserving an existing id could send the designated bearer to an
|
|
783
|
+
// attacker-controlled URL.
|
|
784
|
+
const withoutReservedId = settings.mcpServers.filter(
|
|
785
|
+
(server) => server.id !== CODEX_APPS_MCP_SERVER_ID,
|
|
786
|
+
);
|
|
787
|
+
if (!settings.codexConnectedAppsEnabled || !credentialAvailable) {
|
|
788
|
+
return withoutReservedId.length === settings.mcpServers.length
|
|
789
|
+
? settings
|
|
790
|
+
: { ...settings, mcpServers: withoutReservedId };
|
|
791
|
+
}
|
|
792
|
+
const existing = settings.mcpServers.at(-1);
|
|
735
793
|
if (
|
|
736
|
-
|
|
737
|
-
|
|
794
|
+
withoutReservedId.length === settings.mcpServers.length - 1 &&
|
|
795
|
+
existing !== undefined &&
|
|
796
|
+
Object.keys(existing).length === Object.keys(canonicalServer).length &&
|
|
797
|
+
Object.entries(canonicalServer).every(
|
|
798
|
+
([key, value]) => existing[key as keyof typeof existing] === value,
|
|
799
|
+
)
|
|
738
800
|
) {
|
|
739
801
|
return settings;
|
|
740
802
|
}
|
|
741
803
|
return {
|
|
742
804
|
...settings,
|
|
743
|
-
mcpServers: [
|
|
744
|
-
...settings.mcpServers,
|
|
745
|
-
{
|
|
746
|
-
id: CODEX_APPS_MCP_SERVER_ID,
|
|
747
|
-
name: CODEX_APPS_MCP_SERVER_NAME,
|
|
748
|
-
url: CODEX_APPS_MCP_URL,
|
|
749
|
-
timeoutMs: CODEX_APPS_STARTUP_TIMEOUT_MS,
|
|
750
|
-
// Availability is credential-specific, so discover on every run.
|
|
751
|
-
cacheToolsList: false,
|
|
752
|
-
},
|
|
753
|
-
],
|
|
805
|
+
mcpServers: [...withoutReservedId, canonicalServer],
|
|
754
806
|
};
|
|
755
807
|
}
|
|
756
808
|
|