@opengeni/capabilities 0.2.0 → 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.
package/README.md CHANGED
@@ -20,4 +20,20 @@ Security defaults:
20
20
  - a safe read/query may refresh and retry exactly once on `401`, while a
21
21
  mutation is never replayed after an ambiguous provider authorization result;
22
22
  and
23
- - errors contain structural recovery facts, never provider bodies or secrets.
23
+ - errors contain structural recovery facts, never provider bodies or secrets.
24
+
25
+ ## Local MCP bridge kit
26
+
27
+ `src/mcp-bridge.ts` defines the shared contract for provider APIs exposed as
28
+ in-process MCP servers. A bridge declares a secret-free catalog identity,
29
+ actual authority class, reviewed tool-surface class, 1-32 exact HTTPS
30
+ destinations, and the safe-read-only replay rule. Adapter matching is generic
31
+ and fails closed on ambiguity. The descriptor is not authorization: each
32
+ adapter still revalidates its Connection or host-owned authority before every
33
+ provider request.
34
+
35
+ The Gmail REST adapter is the static reviewed example. OpenAPI and GraphQL
36
+ Integration Definitions keep their existing local MCP adapters without
37
+ claiming this descriptor. Google Drive remains one functional Integration row
38
+ with its existing Connection and facet authority. See
39
+ `docs/design/first-party-mcp-bridges.md`.
package/dist/index.d.ts CHANGED
@@ -2,7 +2,9 @@ export * from "./auth.js";
2
2
  export * from "./graphql.js";
3
3
  export * from "./http.js";
4
4
  export * from "./mcp-manifest.js";
5
+ export * from "./mcp-bridge.js";
5
6
  export * from "./openapi.js";
6
7
  export * from "./integration-definitions.js";
8
+ export * from "./integration-presentations.js";
7
9
  export * from "./revision.js";
8
10
  export * from "./types.js";
package/dist/index.js CHANGED
@@ -619,6 +619,22 @@ async function sendGraphqlRequest(options, request, credential, signal) {
619
619
  headers.set("accept", "application/json");
620
620
  headers.set("content-type", "application/json");
621
621
  if (credential) applyCredentialPlacements(endpoint, headers, credential);
622
+ if (credential?.authorizeProviderRequest) {
623
+ let authorized = false;
624
+ try {
625
+ authorized = await credential.authorizeProviderRequest();
626
+ } catch {
627
+ authorized = false;
628
+ }
629
+ if (!authorized) {
630
+ throw new IntegrationInvocationError(
631
+ "authorization_rejected",
632
+ "The connected account is no longer authorized for this operation",
633
+ "not_started",
634
+ false
635
+ );
636
+ }
637
+ }
622
638
  return await fetchWithDeadline(
623
639
  options.transport,
624
640
  endpoint,
@@ -830,6 +846,63 @@ function basename(value) {
830
846
  return value?.trim().split(/[\\/]/).pop() ?? "";
831
847
  }
832
848
 
849
+ // src/mcp-bridge.ts
850
+ var LOCAL_MCP_BRIDGE_CONTRACT_VERSION = 1;
851
+ function defineLocalMcpBridgeDescriptor(input) {
852
+ const adapterId = boundedIdentity(input.adapterId, "adapterId");
853
+ const providerId = boundedIdentity(input.providerId, "providerId");
854
+ const catalogIdentity = boundedIdentity(input.catalogIdentity, "catalogIdentity", 512);
855
+ if (input.destinations.length === 0 || input.destinations.length > 32) {
856
+ throw new Error("Local MCP bridge must declare 1-32 provider destinations");
857
+ }
858
+ const destinations = input.destinations.map((destination) => {
859
+ const url = new URL(destination.origin);
860
+ if (url.protocol !== "https:" || url.origin !== destination.origin) {
861
+ throw new Error("Local MCP bridge destinations must be exact HTTPS origins");
862
+ }
863
+ if (!destination.pathPrefix.startsWith("/") || destination.pathPrefix.includes("\\") || destination.pathPrefix.includes("?") || destination.pathPrefix.includes("#") || new URL(destination.pathPrefix, url.origin).pathname !== destination.pathPrefix) {
864
+ throw new Error("Local MCP bridge destination pathPrefix must be an absolute URL path");
865
+ }
866
+ return Object.freeze({ origin: url.origin, pathPrefix: destination.pathPrefix });
867
+ });
868
+ return Object.freeze({
869
+ contractVersion: LOCAL_MCP_BRIDGE_CONTRACT_VERSION,
870
+ adapterId,
871
+ providerId,
872
+ catalogIdentity,
873
+ transport: "in_process",
874
+ authority: input.authority,
875
+ toolSurface: input.toolSurface,
876
+ mutationReplay: input.mutationReplay,
877
+ destinations: Object.freeze(destinations)
878
+ });
879
+ }
880
+ function isLocalMcpBridgeServer(server) {
881
+ const bridge = server.bridge;
882
+ return bridge?.contractVersion === LOCAL_MCP_BRIDGE_CONTRACT_VERSION && bridge.transport === "in_process";
883
+ }
884
+ function createLocalMcpBridgeFromAdapters(adapters, config, context) {
885
+ const matches = adapters.filter((adapter2) => adapter2.matches(config));
886
+ if (matches.length === 0) return null;
887
+ if (matches.length > 1) {
888
+ throw new Error(
889
+ `Multiple local MCP bridge adapters matched: ${matches.map((entry) => entry.adapterId).join(", ")}`
890
+ );
891
+ }
892
+ const adapter = matches[0];
893
+ const server = adapter.create(config, context);
894
+ if (server.bridge.adapterId !== adapter.adapterId) {
895
+ throw new Error(`Local MCP bridge adapter ${adapter.adapterId} returned mismatched metadata`);
896
+ }
897
+ return server;
898
+ }
899
+ function boundedIdentity(value, name, max = 128) {
900
+ if (value.length === 0 || value.length > max || /[\u0000-\u001f\u007f]/u.test(value)) {
901
+ throw new Error(`Local MCP bridge ${name} is invalid`);
902
+ }
903
+ return value;
904
+ }
905
+
833
906
  // src/openapi.ts
834
907
  import { load as parseYaml } from "js-yaml";
835
908
  var methods = /* @__PURE__ */ new Set([
@@ -1125,6 +1198,22 @@ async function sendOpenApiRequest(options, binding, args, credential, signal) {
1125
1198
  const headers = buildOperationHeaders(binding, args);
1126
1199
  const body = buildOperationBody(binding, args, headers);
1127
1200
  if (credential) applyCredentialPlacements(url, headers, credential);
1201
+ if (credential?.authorizeProviderRequest) {
1202
+ let authorized = false;
1203
+ try {
1204
+ authorized = await credential.authorizeProviderRequest();
1205
+ } catch {
1206
+ authorized = false;
1207
+ }
1208
+ if (!authorized) {
1209
+ throw new IntegrationInvocationError(
1210
+ "authorization_rejected",
1211
+ "The connected account is no longer authorized for this operation",
1212
+ "not_started",
1213
+ false
1214
+ );
1215
+ }
1216
+ }
1128
1217
  return await fetchWithDeadline(
1129
1218
  options.transport,
1130
1219
  url,
@@ -1517,7 +1606,7 @@ var mailboxFacets = (provider) => [
1517
1606
  provider,
1518
1607
  connectionRequired: true,
1519
1608
  delivery: "poll",
1520
- cursor: provider === "google-gmail" ? "history_id" : "delta_link"
1609
+ cursor: "delta_link"
1521
1610
  }
1522
1611
  },
1523
1612
  {
@@ -1537,7 +1626,7 @@ var mailboxFacets = (provider) => [
1537
1626
  delivery: "email"
1538
1627
  }
1539
1628
  },
1540
- accountIdentityFacet(provider === "google-gmail" ? "google" : "microsoft")
1629
+ accountIdentityFacet("microsoft")
1541
1630
  ];
1542
1631
  var googleDiscoveryUrl = (service, version) => `https://www.googleapis.com/discovery/v1/apis/${service}/${version}/rest`;
1543
1632
  var googleOAuth = (scopes) => ({
@@ -1563,21 +1652,6 @@ var GOOGLE_DRIVE_INTEGRATION_DEFINITION = {
1563
1652
  },
1564
1653
  facets: [driveKnowledgeFacet("google-drive"), accountIdentityFacet("google")]
1565
1654
  };
1566
- var GOOGLE_GMAIL_INTEGRATION_DEFINITION = {
1567
- id: "google-gmail",
1568
- name: "Gmail",
1569
- summary: "Messages, threads, labels, drafts, and sending mail.",
1570
- protocol: "openapi",
1571
- provider: { id: "google", domain: "gmail.googleapis.com" },
1572
- source: { kind: "google_discovery", url: googleDiscoveryUrl("gmail", "v1") },
1573
- baseUrl: "https://gmail.googleapis.com/",
1574
- authentication: googleOAuth(["https://mail.google.com/"]),
1575
- healthCheck: {
1576
- operationKey: "gmail.users.labels.list",
1577
- arguments: { path: { userId: "me" } }
1578
- },
1579
- facets: mailboxFacets("google-gmail")
1580
- };
1581
1655
  var MICROSOFT_GRAPH_OPENAPI_URL = "https://raw.githubusercontent.com/microsoftgraph/msgraph-metadata/master/openapi/v1.0/openapi.yaml";
1582
1656
  var MICROSOFT_GRAPH_BASE_URL = "https://graph.microsoft.com/v1.0";
1583
1657
  var microsoftOAuth = (scopes) => ({
@@ -1702,7 +1776,6 @@ var MICROSOFT_ONEDRIVE_INTEGRATION_DEFINITION = {
1702
1776
  };
1703
1777
  var CORE_INTEGRATION_DEFINITIONS = [
1704
1778
  GOOGLE_DRIVE_INTEGRATION_DEFINITION,
1705
- GOOGLE_GMAIL_INTEGRATION_DEFINITION,
1706
1779
  MICROSOFT_OUTLOOK_MAIL_INTEGRATION_DEFINITION,
1707
1780
  MICROSOFT_OUTLOOK_CALENDAR_INTEGRATION_DEFINITION,
1708
1781
  MICROSOFT_OUTLOOK_CONTACTS_INTEGRATION_DEFINITION,
@@ -1819,9 +1892,7 @@ function collectGoogleMethods(document, value, paths) {
1819
1892
  const path = stringValue2(rawMethod.path);
1820
1893
  const httpMethod = stringValue2(rawMethod.httpMethod)?.toLowerCase();
1821
1894
  if (!path || !httpMethod) continue;
1822
- const parameters = Object.entries(
1823
- isRecord3(rawMethod.parameters) ? rawMethod.parameters : {}
1824
- ).flatMap(([name, rawParameter]) => {
1895
+ const parameters = Object.entries(isRecord3(rawMethod.parameters) ? rawMethod.parameters : {}).sort(([left], [right]) => left.localeCompare(right)).flatMap(([name, rawParameter]) => {
1825
1896
  if (!isRecord3(rawParameter)) return [];
1826
1897
  const location = rawParameter.location === "path" ? "path" : "query";
1827
1898
  return [
@@ -1838,7 +1909,10 @@ function collectGoogleMethods(document, value, paths) {
1838
1909
  const responseRef = isRecord3(rawMethod.response) ? stringValue2(rawMethod.response.$ref) : void 0;
1839
1910
  const operation = {
1840
1911
  operationId: stringValue2(rawMethod.id) ?? fallbackId,
1841
- summary: stringValue2(rawMethod.description) ?? stringValue2(rawMethod.id) ?? fallbackId,
1912
+ // Discovery descriptions are often full documentation paragraphs. Keep
1913
+ // them as descriptions and use the stable method identity for the short
1914
+ // OpenGeni tool display name.
1915
+ summary: stringValue2(rawMethod.id) ?? fallbackId,
1842
1916
  description: stringValue2(rawMethod.description),
1843
1917
  parameters,
1844
1918
  responses: {
@@ -1917,15 +1991,166 @@ function stringValue2(value) {
1917
1991
  function isRecord3(value) {
1918
1992
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1919
1993
  }
1994
+
1995
+ // src/integration-presentations.ts
1996
+ var INTEGRATION_DEFINITION_PRESENTATIONS = {
1997
+ "google-drive": {
1998
+ providerName: "Google",
1999
+ icon: "files",
2000
+ introduction: "Let agents work with files in the Google Drive account you choose.",
2001
+ capabilities: [
2002
+ {
2003
+ title: "Find files and folders",
2004
+ description: "Browse and search content in My Drive and shared drives."
2005
+ },
2006
+ {
2007
+ title: "Create and update content",
2008
+ description: "Work with files and folders through the reviewed Drive tools."
2009
+ },
2010
+ {
2011
+ title: "Manage sharing",
2012
+ description: "Review and update links, permissions, and shared-drive content."
2013
+ }
2014
+ ],
2015
+ permissionSummary: "Google asks for access to the Drive account you approve, including files shared with that account.",
2016
+ scopeLabels: {
2017
+ "https://www.googleapis.com/auth/drive": {
2018
+ label: "Work with Google Drive files",
2019
+ description: "See, create, edit, organize, and share files available to this account."
2020
+ }
2021
+ }
2022
+ },
2023
+ "microsoft-outlook-mail": {
2024
+ providerName: "Microsoft",
2025
+ icon: "mail",
2026
+ introduction: "Let agents work with mail in the Microsoft account you choose.",
2027
+ capabilities: [
2028
+ {
2029
+ title: "Find and understand mail",
2030
+ description: "Search messages, folders, and attachments for useful context."
2031
+ },
2032
+ {
2033
+ title: "Draft and send messages",
2034
+ description: "Prepare, update, and send mail through the reviewed Outlook tools."
2035
+ },
2036
+ {
2037
+ title: "Manage mailbox settings",
2038
+ description: "Work with supported folders, classifications, and mailbox preferences."
2039
+ }
2040
+ ],
2041
+ permissionSummary: "Microsoft asks for mail and mailbox-setting access for the account you approve.",
2042
+ scopeLabels: {
2043
+ "Mail.ReadWrite": {
2044
+ label: "Read and update mail",
2045
+ description: "Work with messages, folders, and attachments in this mailbox."
2046
+ },
2047
+ "Mail.Send": {
2048
+ label: "Send mail",
2049
+ description: "Send messages as the connected Microsoft account."
2050
+ },
2051
+ "MailboxSettings.ReadWrite": {
2052
+ label: "Manage mailbox settings",
2053
+ description: "Read and update supported Outlook mailbox preferences."
2054
+ }
2055
+ }
2056
+ },
2057
+ "microsoft-outlook-calendar": {
2058
+ providerName: "Microsoft",
2059
+ icon: "calendar",
2060
+ introduction: "Let agents help coordinate the calendars in your Microsoft account.",
2061
+ capabilities: [
2062
+ {
2063
+ title: "Understand your schedule",
2064
+ description: "Review calendars, events, availability, and reminders."
2065
+ },
2066
+ {
2067
+ title: "Plan meetings",
2068
+ description: "Find suitable times and coordinate calendar activity."
2069
+ },
2070
+ {
2071
+ title: "Manage events",
2072
+ description: "Create and update events through the reviewed calendar tools."
2073
+ }
2074
+ ],
2075
+ permissionSummary: "Microsoft asks for permission to view and manage calendars for the account you approve.",
2076
+ scopeLabels: {
2077
+ "Calendars.ReadWrite": {
2078
+ label: "View and manage calendars",
2079
+ description: "Read, create, update, and organize calendar events."
2080
+ }
2081
+ }
2082
+ },
2083
+ "microsoft-outlook-contacts": {
2084
+ providerName: "Microsoft",
2085
+ icon: "contacts",
2086
+ introduction: "Let agents work with contacts in your Microsoft account.",
2087
+ capabilities: [
2088
+ {
2089
+ title: "Find people",
2090
+ description: "Look up contacts and relevant people suggestions."
2091
+ },
2092
+ {
2093
+ title: "Organize contacts",
2094
+ description: "Work with contacts and contact folders."
2095
+ },
2096
+ {
2097
+ title: "Keep details current",
2098
+ description: "Create or update contact information through reviewed tools."
2099
+ }
2100
+ ],
2101
+ permissionSummary: "Microsoft asks for contact access and people suggestions for the account you approve.",
2102
+ scopeLabels: {
2103
+ "Contacts.ReadWrite": {
2104
+ label: "View and manage contacts",
2105
+ description: "Read, create, update, and organize contacts and contact folders."
2106
+ },
2107
+ "People.Read.All": {
2108
+ label: "Find relevant people",
2109
+ description: "Use people suggestions available to the connected account."
2110
+ }
2111
+ }
2112
+ },
2113
+ "microsoft-onedrive": {
2114
+ providerName: "Microsoft",
2115
+ icon: "cloud",
2116
+ introduction: "Let agents work with files in the Microsoft account you choose.",
2117
+ capabilities: [
2118
+ {
2119
+ title: "Find files and folders",
2120
+ description: "Browse drives, folders, shared items, and sites available to the account."
2121
+ },
2122
+ {
2123
+ title: "Create and update content",
2124
+ description: "Work with OneDrive and SharePoint files through reviewed tools."
2125
+ },
2126
+ {
2127
+ title: "Manage sharing",
2128
+ description: "Review and update sharing links and permissions."
2129
+ }
2130
+ ],
2131
+ permissionSummary: "Microsoft asks for file and site access anywhere the connected account already has access.",
2132
+ scopeLabels: {
2133
+ "Files.ReadWrite.All": {
2134
+ label: "Work with accessible files",
2135
+ description: "Read, create, update, and organize files available to this account."
2136
+ },
2137
+ "Sites.ReadWrite.All": {
2138
+ label: "Work with accessible sites",
2139
+ description: "Read and update files in SharePoint sites available to this account."
2140
+ }
2141
+ }
2142
+ }
2143
+ };
1920
2144
  export {
1921
2145
  CORE_INTEGRATION_DEFINITIONS,
1922
2146
  DEFAULT_INTEGRATION_RESPONSE_BYTES,
1923
2147
  DEFAULT_INTEGRATION_TIMEOUT_MS,
1924
2148
  GOOGLE_DRIVE_INTEGRATION_DEFINITION,
1925
- GOOGLE_GMAIL_INTEGRATION_DEFINITION,
1926
2149
  GraphqlMcpServer,
2150
+ INTEGRATION_DEFINITION_PRESENTATIONS,
1927
2151
  IntegrationInvocationError,
1928
2152
  IntegrationProtocolError,
2153
+ LOCAL_MCP_BRIDGE_CONTRACT_VERSION,
1929
2154
  MAX_INTEGRATION_SPEC_BYTES,
1930
2155
  MAX_INTEGRATION_TOOLS,
1931
2156
  MICROSOFT_GRAPH_BASE_URL,
@@ -1941,8 +2166,10 @@ export {
1941
2166
  compileGraphqlRevision,
1942
2167
  compileOpenApiRevision,
1943
2168
  createGraphqlMcpServer,
2169
+ createLocalMcpBridgeFromAdapters,
1944
2170
  createOpenApiMcpServer,
1945
2171
  createPinnedIntegrationTransport,
2172
+ defineLocalMcpBridgeDescriptor,
1946
2173
  deriveMcpNamespace,
1947
2174
  directIntegrationTransport,
1948
2175
  discoverOpenApiAuth,
@@ -1958,6 +2185,7 @@ export {
1958
2185
  integrationFacetDefinitions,
1959
2186
  invokeGraphqlOperation,
1960
2187
  invokeOpenApiOperation,
2188
+ isLocalMcpBridgeServer,
1961
2189
  parseOpenApiDocument,
1962
2190
  readIntegrationResponse,
1963
2191
  sha256Hex,