@opengeni/capabilities 0.1.1 → 0.3.0-canary.0

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.
@@ -0,0 +1,117 @@
1
+ import type { MCPServer } from "@openai/agents";
2
+
3
+ export const LOCAL_MCP_BRIDGE_CONTRACT_VERSION = 1 as const;
4
+
5
+ export type LocalMcpBridgeAuthority = "connection" | "host" | "none";
6
+ export type LocalMcpBridgeToolSurface = "static_reviewed";
7
+
8
+ export type LocalMcpBridgeDestination = Readonly<{
9
+ origin: string;
10
+ pathPrefix: string;
11
+ }>;
12
+
13
+ /**
14
+ * Secret-free description of an in-process provider-to-MCP adapter.
15
+ *
16
+ * This is observability and registration metadata, not authorization. The
17
+ * adapter must still revalidate its named authority before each physical
18
+ * provider request and keep credentials outside tool results and schemas.
19
+ */
20
+ export type LocalMcpBridgeDescriptor = Readonly<{
21
+ contractVersion: typeof LOCAL_MCP_BRIDGE_CONTRACT_VERSION;
22
+ adapterId: string;
23
+ providerId: string;
24
+ catalogIdentity: string;
25
+ transport: "in_process";
26
+ authority: LocalMcpBridgeAuthority;
27
+ toolSurface: LocalMcpBridgeToolSurface;
28
+ mutationReplay: "safe_reads_only";
29
+ destinations: readonly LocalMcpBridgeDestination[];
30
+ }>;
31
+
32
+ export interface LocalMcpBridgeServer extends MCPServer {
33
+ readonly bridge: LocalMcpBridgeDescriptor;
34
+ }
35
+
36
+ export interface LocalMcpBridgeAdapter<TConfig, TContext> {
37
+ readonly adapterId: string;
38
+ matches(config: TConfig): boolean;
39
+ create(config: TConfig, context: TContext): LocalMcpBridgeServer;
40
+ }
41
+
42
+ export function defineLocalMcpBridgeDescriptor(
43
+ input: Omit<LocalMcpBridgeDescriptor, "contractVersion" | "transport">,
44
+ ): LocalMcpBridgeDescriptor {
45
+ const adapterId = boundedIdentity(input.adapterId, "adapterId");
46
+ const providerId = boundedIdentity(input.providerId, "providerId");
47
+ const catalogIdentity = boundedIdentity(input.catalogIdentity, "catalogIdentity", 512);
48
+ if (input.destinations.length === 0 || input.destinations.length > 32) {
49
+ throw new Error("Local MCP bridge must declare 1-32 provider destinations");
50
+ }
51
+ const destinations = input.destinations.map((destination) => {
52
+ const url = new URL(destination.origin);
53
+ if (url.protocol !== "https:" || url.origin !== destination.origin) {
54
+ throw new Error("Local MCP bridge destinations must be exact HTTPS origins");
55
+ }
56
+ if (
57
+ !destination.pathPrefix.startsWith("/") ||
58
+ destination.pathPrefix.includes("\\") ||
59
+ destination.pathPrefix.includes("?") ||
60
+ destination.pathPrefix.includes("#") ||
61
+ new URL(destination.pathPrefix, url.origin).pathname !== destination.pathPrefix
62
+ ) {
63
+ throw new Error("Local MCP bridge destination pathPrefix must be an absolute URL path");
64
+ }
65
+ return Object.freeze({ origin: url.origin, pathPrefix: destination.pathPrefix });
66
+ });
67
+ return Object.freeze({
68
+ contractVersion: LOCAL_MCP_BRIDGE_CONTRACT_VERSION,
69
+ adapterId,
70
+ providerId,
71
+ catalogIdentity,
72
+ transport: "in_process",
73
+ authority: input.authority,
74
+ toolSurface: input.toolSurface,
75
+ mutationReplay: input.mutationReplay,
76
+ destinations: Object.freeze(destinations),
77
+ });
78
+ }
79
+
80
+ export function isLocalMcpBridgeServer(server: MCPServer): server is LocalMcpBridgeServer {
81
+ const bridge = (server as Partial<LocalMcpBridgeServer>).bridge;
82
+ return (
83
+ bridge?.contractVersion === LOCAL_MCP_BRIDGE_CONTRACT_VERSION &&
84
+ bridge.transport === "in_process"
85
+ );
86
+ }
87
+
88
+ /**
89
+ * Select exactly one adapter for a runtime catalog row. Ambiguous matches fail
90
+ * closed so adding a bridge cannot silently replace another provider route.
91
+ */
92
+ export function createLocalMcpBridgeFromAdapters<TConfig, TContext>(
93
+ adapters: readonly LocalMcpBridgeAdapter<TConfig, TContext>[],
94
+ config: TConfig,
95
+ context: TContext,
96
+ ): LocalMcpBridgeServer | null {
97
+ const matches = adapters.filter((adapter) => adapter.matches(config));
98
+ if (matches.length === 0) return null;
99
+ if (matches.length > 1) {
100
+ throw new Error(
101
+ `Multiple local MCP bridge adapters matched: ${matches.map((entry) => entry.adapterId).join(", ")}`,
102
+ );
103
+ }
104
+ const adapter = matches[0]!;
105
+ const server = adapter.create(config, context);
106
+ if (server.bridge.adapterId !== adapter.adapterId) {
107
+ throw new Error(`Local MCP bridge adapter ${adapter.adapterId} returned mismatched metadata`);
108
+ }
109
+ return server;
110
+ }
111
+
112
+ function boundedIdentity(value: string, name: string, max = 128): string {
113
+ if (value.length === 0 || value.length > max || /[\u0000-\u001f\u007f]/u.test(value)) {
114
+ throw new Error(`Local MCP bridge ${name} is invalid`);
115
+ }
116
+ return value;
117
+ }
package/src/openapi.ts CHANGED
@@ -55,7 +55,7 @@ export interface OpenApiOperationBinding {
55
55
  export type OpenApiRevision = IntegrationRevision<OpenApiOperationBinding, "openapi">;
56
56
 
57
57
  export interface CompileOpenApiOptions {
58
- readonly integrationId: string;
58
+ readonly definitionId: string;
59
59
  readonly sourceUrl?: string;
60
60
  readonly baseUrl?: string;
61
61
  readonly provider?: string;
@@ -212,13 +212,13 @@ export function compileOpenApiRevision(
212
212
  return {
213
213
  id: revisionId,
214
214
  protocol: "openapi",
215
- integrationId: options.integrationId,
215
+ definitionId: options.definitionId,
216
216
  contentSha256,
217
217
  source: {
218
218
  ...(options.sourceUrl ? { url: options.sourceUrl } : {}),
219
219
  ...(options.provider ? { provider: options.provider } : {}),
220
220
  },
221
- title: stringValue(info.title) ?? options.integrationId,
221
+ title: stringValue(info.title) ?? options.definitionId,
222
222
  ...(stringValue(info.description) ? { description: stringValue(info.description)! } : {}),
223
223
  ...(stringValue(info.version) ? { version: stringValue(info.version)! } : {}),
224
224
  tools,
@@ -261,7 +261,7 @@ export class OpenApiMcpServer implements MCPServer {
261
261
  readonly name: string;
262
262
 
263
263
  constructor(private readonly options: OpenApiServerOptions) {
264
- this.name = `openapi:${stableToolId(options.revision.integrationId)}`;
264
+ this.name = `openapi:${stableToolId(options.revision.definitionId)}`;
265
265
  }
266
266
 
267
267
  async connect(): Promise<void> {}
@@ -395,7 +395,7 @@ async function resolveOpenApiCredential(
395
395
  const credential = await options.credentialResolver.resolve({
396
396
  ...options.authority,
397
397
  protocol: "openapi",
398
- integrationId: options.revision.integrationId,
398
+ definitionId: options.revision.definitionId,
399
399
  revisionId: options.revision.id,
400
400
  operationKey: toolId,
401
401
  destinationUrl,
@@ -426,6 +426,22 @@ async function sendOpenApiRequest(
426
426
  const headers = buildOperationHeaders(binding, args);
427
427
  const body = buildOperationBody(binding, args, headers);
428
428
  if (credential) applyCredentialPlacements(url, headers, credential);
429
+ if (credential?.authorizeProviderRequest) {
430
+ let authorized = false;
431
+ try {
432
+ authorized = await credential.authorizeProviderRequest();
433
+ } catch {
434
+ authorized = false;
435
+ }
436
+ if (!authorized) {
437
+ throw new IntegrationInvocationError(
438
+ "authorization_rejected",
439
+ "The connected account is no longer authorized for this operation",
440
+ "not_started",
441
+ false,
442
+ );
443
+ }
444
+ }
429
445
  return await fetchWithDeadline(
430
446
  options.transport,
431
447
  url,
package/src/types.ts CHANGED
@@ -37,6 +37,8 @@ export interface IntegrationCredentialAudience {
37
37
  export interface ResolvedIntegrationCredential {
38
38
  readonly audience: IntegrationCredentialAudience;
39
39
  readonly placements: readonly IntegrationCredentialPlacement[];
40
+ /** Exact accepted-attempt fence invoked immediately before one HTTP request. */
41
+ readonly authorizeProviderRequest?: () => Promise<boolean>;
40
42
  readonly expiresAt?: string;
41
43
  readonly scope?: readonly string[];
42
44
  }
@@ -54,7 +56,7 @@ export interface IntegrationInvocationAuthority {
54
56
 
55
57
  export interface ResolveIntegrationCredentialRequest extends IntegrationInvocationAuthority {
56
58
  readonly protocol: Exclude<IntegrationProtocol, "mcp">;
57
- readonly integrationId: string;
59
+ readonly definitionId: string;
58
60
  readonly revisionId: string;
59
61
  readonly operationKey: string;
60
62
  readonly destinationUrl: string;
@@ -90,7 +92,7 @@ export interface IntegrationRevision<
90
92
  > {
91
93
  readonly id: string;
92
94
  readonly protocol: TProtocol;
93
- readonly integrationId: string;
95
+ readonly definitionId: string;
94
96
  readonly contentSha256: string;
95
97
  readonly source: IntegrationRevisionSource;
96
98
  readonly title: string;
@@ -1,44 +0,0 @@
1
- export interface OAuthProviderPreset {
2
- readonly authorizationUrl: string;
3
- readonly tokenUrl: string;
4
- readonly scopes: readonly string[];
5
- readonly tokenPlacement: {
6
- readonly carrier: "header";
7
- readonly name: "Authorization";
8
- readonly prefix: "Bearer ";
9
- };
10
- }
11
- export interface OpenApiProviderPreset {
12
- readonly id: string;
13
- readonly name: string;
14
- readonly summary: string;
15
- readonly family: "google" | "microsoft";
16
- readonly sourceFormat: "google-discovery" | "openapi";
17
- readonly sourceUrl: string;
18
- readonly baseUrl: string;
19
- readonly oauth: OAuthProviderPreset;
20
- readonly pathPrefixes?: readonly string[];
21
- readonly healthOperation?: string;
22
- readonly healthArgs?: Readonly<Record<string, unknown>>;
23
- readonly features: readonly IntegrationFeatureDefinition[];
24
- }
25
- export interface IntegrationFeatureDefinition {
26
- readonly featureKey: string;
27
- readonly kind: "knowledge_source" | "inbound_trigger" | "delivery_destination" | "identity_link";
28
- readonly configSchema: Readonly<Record<string, unknown>>;
29
- readonly capabilities: Readonly<Record<string, unknown>>;
30
- }
31
- export declare const GOOGLE_DRIVE_PRESET: OpenApiProviderPreset;
32
- export declare const GOOGLE_GMAIL_PRESET: OpenApiProviderPreset;
33
- export declare const MICROSOFT_GRAPH_OPENAPI_URL = "https://raw.githubusercontent.com/microsoftgraph/msgraph-metadata/master/openapi/v1.0/openapi.yaml";
34
- export declare const MICROSOFT_GRAPH_BASE_URL = "https://graph.microsoft.com/v1.0";
35
- export declare const MICROSOFT_OUTLOOK_MAIL_PRESET: OpenApiProviderPreset;
36
- export declare const MICROSOFT_OUTLOOK_CALENDAR_PRESET: OpenApiProviderPreset;
37
- export declare const MICROSOFT_OUTLOOK_CONTACTS_PRESET: OpenApiProviderPreset;
38
- export declare const MICROSOFT_ONEDRIVE_PRESET: OpenApiProviderPreset;
39
- export declare const CORE_PROVIDER_PRESETS: readonly OpenApiProviderPreset[];
40
- export declare function providerPresetById(id: string): OpenApiProviderPreset | undefined;
41
- export declare function providerDomainForPreset(preset: OpenApiProviderPreset): string;
42
- export declare function integrationFeaturesForPreset(presetId: string | null | undefined): readonly IntegrationFeatureDefinition[];
43
- export declare function filterOpenApiDocumentForPreset(document: Record<string, unknown>, preset: OpenApiProviderPreset): Record<string, unknown>;
44
- export declare function googleDiscoveryToOpenApi(discovery: unknown): Record<string, unknown>;