# Konnektoren

Wie Konnektoren und Verbindungen Agents einen begrenzten Zugriff auf externe Tools ermöglichen.

Canonical page: https://beeuni.ai/docs/de/connect/connectors

Ein Konnektor verknüpft ein Projekt mit einem externen Tool oder Dienst. Der Agent
ruft ihn als Tool auf. Beeuni vermittelt jeden Aufruf, sodass die Sandbox niemals
die Zugangsdaten des Konnektors enthält.

Die meisten Konnektoren deklarieren Sie in `beeuni.yaml`. Eine Übersicht
über jedes Feld finden Sie in der [Manifestreferenz](/docs/de/project/manifest). Beeuni deklariert
Kanal- und Computerkonnektoren, wenn Sie eine Chatplattform oder einen Computer
verbinden.

<a id="browse-and-add-a-connector"></a>

## Konnektor durchsuchen und hinzufügen

Öffnen Sie **Connectors**, um den verwalteten Katalog zu durchsuchen. Die
Standardliste enthält Toolkits verwalteter Anbieter, die mit einer vom Anbieter
verwalteten Authentifizierung oder einer aktivierten benutzerdefinierten
Authentifizierungskonfiguration verbunden werden können. Eine bestehende
Verbindung in Ihrem Projekt ist dafür nicht erforderlich. Ein Toolkit, das eine
nicht verifizierte benutzerdefinierte OAuth-Konfiguration benötigt, bleibt
verborgen, bis diese Konfiguration verifiziert werden kann.

Aktivieren Sie für direkte Quellen **Connectors API Discover** in den
Feature-Flags des Projekts und wählen Sie anschließend auf derselben Seite
**API / MCP** aus. Das Aktivieren des Flags ersetzt nicht den verwalteten
Standard. Der direkte Katalog gruppiert veröffentlichte OpenAPI-, MCP-,
GraphQL-, Postman- und andere API-Oberflächen. Wählen Sie eine Karte aus,
wählen Sie eine veröffentlichte Oberfläche und schließen Sie deren
Verbindungsformular ab. Oberflächen, die nur Dokumentation enthalten, öffnen
die Dokumentation des Anbieters; sie werden nicht als sofort verbindbare
Vorlage angeboten. Verwenden Sie **Add → Manual** für eine rohe API oder ein
Schema, das der Katalog nicht enthält. Die direkte Suche funktioniert auch ohne
einen konfigurierten verwalteten Anbieter.

<a id="connectors-connections-and-accounts"></a>

## Konnektoren, Verbindungen und Konten

Ein Konnektor ist das zugriffsorientierte Paket für den Agenten: eine deklarierte
Fähigkeit (welche Aktionen, wie der Dienst erreicht wird). Er ist keine Rolle
und enthält keine Beeuni-Berechtigung: Ein Agent erreicht einen Konnektor nur,
wenn sein Manifest-Grant den Slug aufführt und das Rollenurteil den Aufruf
zulässt. Siehe [Ein Vokabular, zwei Bindungen](/docs/de/accounts#one-vocabulary-two-bindings). Ein
Konnektor enthält:

- einen im Projekt eindeutigen Slug
- einen Anzeigenamen
- eine Anbieter-App
- Konnektor-Richtlinien

Eine Verbindung ist ein **Konto** — eine autorisierte Identität — für den
Konnektor: eine Zugangsdaten, ein OAuth-Grant oder ein API-Schlüssel. Ein
Konnektor kann mehrere Konten nebeneinander enthalten. Jedes Konto verwendet
die Richtlinien des Konnektors. Das `owner_type` jedes Kontos bestimmt, wer einen
Aufruf als dieses Konto ausführen darf:

- `project` — ein **gemeinsam genutztes** Konto. Es ist für alle erreichbar,
denen der Konnektor gewährt wurde, für Menschen oder Dienstkonten (Agent,
Trigger).
- `member` — ein **privates** Konto, das einem Projektmitglied
(`owner_id`) gehört. Es ist nur für dieses Mitglied und nur in einer **privaten**
Sitzung erreichbar. Ein Dienstkonto (ein Agent oder ein unbeaufsichtigt
handelnder Trigger) kann niemals als privates Konto eines Mitglieds ausführen.

Mehrere Konnektoren können auf dieselbe Anbieter-App verweisen. Verwenden Sie
separate Konnektoren, wenn eine App unterschiedliche Richtlinien benötigt.

<a id="add-an-account"></a>

### Konto hinzufügen

Öffnen Sie den Konnektor unter **Customize → Connectors**. Der Tab
**Accounts** listet alle Konten, die Sie verwenden oder verwalten können, in
einer Liste auf. Jede Karte zeigt, wer das Konto verwenden kann: **Only you**,
**Everyone in project** oder die Gruppen und Personen, mit denen es geteilt ist.

Wählen Sie **Add account**, geben Sie dem Konto einen Namen und wählen Sie
**Who can use it**:

- **Only you** — ein privates Konto. Jedes Mitglied kann eines hinzufügen.
- **Everyone in the project** — ein gemeinsam genutztes Konto.
- **Specific people or groups** — ein gemeinsam genutztes Konto, beschränkt auf
die ausgewählten Personen, Gruppen und Agenten.

Die beiden gemeinsam genutzten Optionen benötigen `project.connector.connections.manage`. Für
**Specific people or groups** schreibt Beeuni die Grants, bevor Sie das Konto
autorisieren, sodass das Konto niemals eine Zugangsdaten enthält, während es
dem gesamten Projekt offensteht. Ein Kontoname muss neu sein: Ein Name, den ein
Konto desselben Eigentümers bereits verwendet, wird abgelehnt.

Wenn ein Agent ein Konto benötigt, stellt er eine **Connect**-Karte im Chat ein.
Die Karte öffnet denselben Dialog, wobei der vom Agenten vorgeschlagene Name
bereits eingetragen und die angeforderte Zielgruppe vorausgewählt ist. Beeuni
erstellt ein neues Konto, autorisiert ein bestehendes niemals erneut und teilt
dem Agenten den Namen des neuen Kontos mit, damit er Aufrufe als dieses Konto
ausführen kann.

<a id="choose-who-can-use-a-shared-account"></a>

### Auswählen, wer ein gemeinsam genutztes Konto verwenden darf

Ein gemeinsam genutztes Konto kann zunächst von allen im Projekt verwendet
werden, bis Sie den Zugriff einschränken. Wählen Sie auf der Kontokarte
**Share** aus. Der Dialog entspricht dem für Agenten verwendeten Dialog
**Grant access**. Er listet auf, wer das Konto derzeit verwenden kann, und Sie
fügen Folgendes hinzu:

- **Everyone in the project** — die Standardeinstellung.
- **Groups** — jedes Mitglied jeder ausgewählten Gruppe.
- **People** — jeweils ein Mitglied. Wählen Sie nur sich selbst aus, um das
Konto auf sich zu beschränken.
- **Agents** — jede Sitzung dieses Agenten, einschließlich Triggern und
geteilten Sitzungen. Jeder, der den Agenten ausführen kann, kann das Konto über
ihn verwenden.

Bis Sie **Save** auswählen, ändert sich nichts. Wenn Sie die letzte Gruppe oder
Person entfernen, kann das Konto wieder von allen verwendet werden; der Dialog
zeigt das Ergebnis an, bevor Sie speichern.

Für ein eingeschränktes Konto gelten die Regeln für private Konten, wobei die
Zielgruppe an die Stelle des Eigentümers tritt:

- Eine Person in der Zielgruppe kann es verwenden, und zwar nur in einer
privaten Sitzung.
- Ein Agent in der Zielgruppe kann es in jeder seiner Sitzungen verwenden.
- Jeder andere Agent und jeder Trigger eines anderen Agenten verwendet es nie.
- Eine Sitzung, die es bindet, kann nicht geteilt werden, es sei denn, das Konto
ist mit dem Agenten dieser Sitzung selbst geteilt.
- Nur eine Person kann ändern, wer ein Konto verwenden darf. Eine Agentensitzung
erhält `403`.

Eine Person außerhalb der Zielgruppe sieht das Konto nicht. Eine Person, die
die Verbindungen des Projekts verwaltet, sieht es weiterhin mit dem Hinweis
**Not shared with you**, damit sie ändern kann, wer es verwenden darf.

<a id="share-your-own-private-account"></a>

### Eigenes privates Konto teilen

Ihr eigenes Konto **Only you** verfügt ebenfalls über eine Schaltfläche
**Share**. Durch das Teilen wird es zu einem gemeinsam genutzten Konto für die
ausgewählten Personen und Gruppen (Sie bleiben dabei, sofern Sie sich nicht
selbst entfernen) oder für alle im Projekt. Ab diesem Zeitpunkt ist es ein
gemeinsam genutztes Konto: Personen, die die Verbindungen des Projekts
verwalten, können es ebenfalls verwalten.

- Das Teilen benötigt `project.connector.connections.manage`, dieselbe Berechtigung wie das Hinzufügen eines
gemeinsam genutzten Kontos. Ohne diese Berechtigung ist die Schaltfläche
deaktiviert und erklärt den Grund.
- Beeuni schreibt zuerst die Grants und wandelt das Konto in einer einzigen
Aktualisierung in ein gemeinsam genutztes Konto um, sodass es zwischenzeitlich
niemals dem gesamten Projekt offensteht.
- Ein gemeinsam genutztes Konto mit demselben Namen auf dem Konnektor blockiert
den Vorgang (`409`): Benennen Sie zuerst eines um.

```text
POST /projects/{projectId}/connections/{connectionId}/share
     {"principals": [{"principal_type": "group", "principal_id": "<group-id>"}]}
```

Eine leere `principals`-Liste teilt das Konto mit allen. Über die CLI:
`beeuni connectors connections share <connection-id> --group <group-id>`
(auch `--user <email|id>`, wiederholbar, oder `--everyone`).

Jeder Zielgruppeneintrag ist eine `connection`-Objektzuweisung im Grant-Speicher:

```text
POST   /accounts/{accountId}/iam/assignments
       {"principal_type": "group", "principal_id": "<group-id>",
        "role_key": "agent-user", "scope_type": "project", "scope_id": "<project-id>",
        "object_type": "connection", "object_id": "<connection-id>"}
DELETE /accounts/{accountId}/iam/assignments/{assignmentId}
```

Über die CLI führen dieselben Schreibvorgänge zu:

```bash
beeuni access grant --group <group-id> --connection <connection-id>
beeuni access grant --everyone --connection <connection-id>
beeuni access revoke <assignment-id>
beeuni connectors connections ls   # the WHO CAN USE column
```

- `principal_type` ist `user`, `group` oder `project` (alle im Projekt;
  `principal_id` ist die Projekt-ID).
- Das Gewähren oder Entziehen eines einzelnen Zugriffs benötigt `project.connector.connections.manage`.
- Nur ein gemeinsam genutztes Konto kann über diese Grants eingeschränkt werden.
Ein privates Konto oder eine ID, die keine Verbindung in diesem Projekt ist,
antwortet mit `404`; teilen Sie Ihr eigenes privates Konto stattdessen über
die oben genannte Route `share`.
- `GET /projects/{projectId}/connections` gibt die Grants jedes gemeinsam genutzten Kontos in `shared_with`
zurück und `usable: false` für ein Konto, das der Aufrufer nur zur Verwaltung sieht.
Die Sitzungsauswahl bietet nur verwendbare Konten an.

<a id="which-identity-an-account-acts-as"></a>

### Als welche Identität ein Konto agiert

Der `label` eines Kontos ist ein vor der Autorisierung gewählter Name. Er gibt nicht an,
welcher Login verwendet wurde. Das tut `connected_as`: die E-Mail-Adresse, der Login oder der Anzeigename,
den der Anbieter für das autorisierte Konto meldet.

- Beeuni liest ihn, wenn eine verwaltete Autorisierung abgeschlossen wird: zuerst den Anzeigenamen des verbundenen
  Kontos, dann das „Wer bin ich“-Tool des Toolkits (Gmail, Google
  Calendar, Google Drive, Linear, GitHub, Slack, Notion, Outlook, Microsoft
  Teams, HubSpot, Jira, Asana, Figma, Airtable, Salesforce, Trello, Dropbox,
  Calendly). Google Docs und Google Sheets stellen kein solches Tool bereit, daher bleibt ihr
  `connected_as` `null`.
- Ein Konto, das weiterhin ein Standardlabel trägt (`Private connection`,
  `Project connection` oder den Namen des Connectors), wird auf diese Identität umbenannt.
  Ein von jemandem gewähltes Label wird niemals ersetzt.
- Die Verbindungsseite zeigt sofort „Verbunden als …“, sobald das Konto geladen ist, sodass ein
  mit einem persönlichen Login autorisiertes gemeinsames Konto sofort sichtbar ist.
- `connected_as` wird bei jeder Verbindung (`GET /projects/{projectId}/connections`),
  in der Kontoliste, in `beeuni connectors accounts <slug>` und
  `beeuni connectors connections ls` (der Spalte `CONNECTED AS`) sowie in den
  Kontozeilen unter **Anpassen → Connectors** angezeigt.

<a id="rename-an-account"></a>

### Konto umbenennen

Benenne ein Konto um, ohne es erneut zu autorisieren:

```text
PUT /projects/{projectId}/connections/{connectionId}/label   {"label": "Support inbox"}
beeuni connectors connections rename <connection-id> Support inbox
```

Öffne im Dashboard den Connector und wähle in der Kontenzeile **⋯ → Umbenennen**.
Nur das Label wird geändert. Das autorisierte Konto, sein Besitzer, sein Standardattribut
und der Anbieterstatus bleiben unverändert. Es gelten dieselben Voraussetzungen wie beim
Trennen: dein eigenes privates Konto oder `project.connector.connections.manage`
bei einem gemeinsamen Konto.

Eine Umbenennung wird mit `400` für `me`, `project` oder ein UUID-ähnliches Label abgelehnt,
weil `--account` diese vor Labels auflöst. Sie wird mit `409` abgelehnt, wenn
bereits ein anderes Konto desselben Besitzers dieses Label trägt; der Vergleich
achtet nicht auf Groß- und Kleinschreibung.

<a id="connect-a-different-account"></a>

### Ein anderes Konto verbinden

Ein Verbindungslink für einen Slot, der bereits ein aktives Konto enthält, autorisiert es nicht erneut.
Der Anbieter verwendet das Konto wieder, und die Verbindungsseite zeigt
**Bereits verbunden**. Wenn du einen anderen Login verwenden möchtest, füge im Connector ein
neues Konto hinzu, mache es zum Standardkonto und trenne anschließend das alte Konto.

Ein Aufruf ohne Angabe eines Kontos wird zuerst zum eigenen privaten Standardkonto des Aufrufers aufgelöst,
dann zum gemeinsamen Standardkonto des Projekts. Jedes Aufrufergebnis gibt an, als welches Konto es ausgeführt wurde (`account: { connection_id, label,
owner_type }`), sodass das Transkript immer die Identität des verwendeten Tool-Aufrufs zeigt.
Liste mit `GET /connectors/projects/{projectId}/connectors/{slug}/accounts` die Konten auf, als die ein Connector aufgerufen werden kann, das Standardkonto zuerst.

> **Warning**
> `authorization_strategy` (`project` | `user`) war ein Connector-weites MODE, das projektbezogene und mitgliedsbezogene Konten gegenseitig ausschloss – ein Connector mit `user`-Strategie konnte kein gemeinsames Konto anbieten und hatte daher überall dort keinen Verbindungsablauf, wo ein Dienstkonto verwendet werden konnte. Es ist veraltet: Manifest und
> `PUT .../authorization-strategy` akzeptieren es weiterhin und antworten fehlerfrei, aber
> nichts liest es mehr. `owner_type` für jede Verbindung ist jetzt die gesamte Zugriffsregel.

<a id="providers"></a>

## Anbieter

Ein Connector verwendet einen Anbietertyp:

- **composio** — verwaltetes OAuth für unterstützte SaaS-Apps
- **pipedream** — veraltetes verwaltetes OAuth, nur für Rollbacks beibehalten
- **openapi**, **postman**, **graphql**, **http** — direkte API-Connectoren
- **mcp** — ein entfernter MCP-Server über HTTP oder SSE
- **channel** — eine Verbindung zu einer Chatplattform
- **computer** — der verbundene Computer jedes Mitglieds ist jeweils ein Konto

Siehe [Slack und Channels](/docs/de/connect/slack) und
[Computer](/docs/de/connect/computers) für die verwalteten Anbieterabläufe.

<a id="apps-that-need-your-own-oauth-app"></a>

### Verfügbarkeit von Apps

Der Connector-Katalog zeigt die Apps, die derzeit verbunden werden können. Einige Apps benötigen eine zusätzliche Authentifizierungskonfiguration und erscheinen erst, wenn diese abgeschlossen ist.

## Authentifizierung und Richtlinien

Eine Verbindung authentifiziert sich über:

- Verwaltetes OAuth, eine Channel-Installation oder einen nativen OAuth2-Grant
- einen über das Dashboard eingegebenen API-Schlüssel oder Token

Beeuni verschlüsselt Verbindungsdaten und löst sie serverseitig für jeden Tool-Aufruf auf. Der Agent fordert eine Aktion an. Beeuni fügt die Zugangsdaten hinzu, prüft den Agent-Grant und die Connector-Verbindungsrichtlinie, ruft die externe API auf und gibt das Ergebnis zurück.

Connector-Richtlinien gehören zum Connector. Eine Verbindung kann sie nicht überschreiben. Projektschutzvorgaben gelten zusätzlich zu den Connector-Verbindungsrichtlinien.

Standardmäßig wird eine nicht zugeordnete Connector-Aktion ohne Genehmigung ausgeführt. Setze
`policy.default_mode: risk`, um für nicht zugeordnete Schreib- und
Destruktivaktionen eine Genehmigung zu verlangen. Setze `sensitive: true`, damit `require_approval` zum
Standard für nicht zugeordnete Aktionen des Connectors wird, einschließlich Lesevorgängen. Explizite Projekt- oder Connector-Verbindungsregeln haben weiterhin Vorrang.

<a id="approve-one-governed-call"></a>

### Einen gesteuerten Aufruf genehmigen

`require_approval` erstellt eine Entscheidung für einen einzelnen Connector-Aufruf. Der Connector
gibt `202 pending_approval` mit `approval_url`, `approval_summary` und
`execution_id` zurück. Eine HTTP-Anfrage bleibt dabei nicht offen.

Teile `approval_url` mit beliebigen Teammitgliedern. Die URL identifiziert die Anfrage, gewährt aber keine Berechtigung. Die Seite erfordert ein angemeldetes Beeuni-Konto. Beeuni prüft anschließend, ob das Konto im Projekt auf Aktionen zugreifen und sie genehmigen kann.

Die Genehmigungsseite zeigt die redigierten Parameter, die der Connector erhält.
Ein Aufrufer kann `approval_context` hinzufügen (CLI: `--reason`), um die Auswirkung zu beschreiben.
Verwende dies, wenn die Parameter nur Verweise sind: `gmail.send_draft` erhält eine
Entwurfs-ID, daher gibt der Agent Empfänger, Betreff und Text an. Die Seite zeigt
diesen Text als Beschreibung des Agents, nicht als verifiziert. Die Parameter bleiben
der Nachweis. Beeuni sendet `approval_context` niemals an den Anbieter.

Genehmige oder lehne den Aufruf einmalig ab. Füge der Entscheidung optional eine Nachricht hinzu. Die Nachricht wird zusammen mit der Entscheidung an den Agenten zurückgesendet, sodass eine Ablehnung angeben kann, was stattdessen zu tun ist.

Jeder ausstehende Aufruf erscheint außerdem unter **Überprüfung → Deine Aufmerksamkeit** für das Projekt. Öffne **Überprüfung** über die Seitenleiste; die Anzahl zeigt, wie viele Elemente auf dich warten. Ein Aufruf wird in derselben Genehmigungsansicht wie über seinen Genehmigungslink geöffnet, sodass du vor der Entscheidung den Connector, die Parameter und die Beschreibung des Agents siehst.

Wenn der Aufruf aus einer Slack- oder Teams-Sitzung stammt, postet Beeuni eine Genehmigungskarte im betreffenden Thread. Auf der Karte stehen die Beschreibung des Agents, die Parameter und **Approve** / **Deny**. In Slack öffnet **Reply…** ein Feld für eine Nachricht an den Agent; in Teams ist das Nachrichtenfeld direkt in der Karte eingebettet. Entscheiden dürfen nur ein Projektmanager oder die Person, die die Sitzung gestartet hat. Eine Entscheidung an beliebiger Stelle (im Thread, in Beeuni oder auf der Genehmigungsseite) ersetzt die Schaltflächen der Karte durch das Ergebnis, und der Agent fährt im selben Thread fort. Beeuni übermittelt die Entscheidung über einen dauerhaften Callback zurück an die Sitzung. Eine Genehmigung gilt nur für den exakten Anfrage-Digest. Bei geändertem Empfänger, Betreff, Text, Kanal, URL oder anderen Parametern ist eine neue Entscheidung erforderlich.

Öffne den **Audit**-Bereich der Sitzung, um dieselbe Parameteransicht zu verwenden. Historische Einträge bleiben schreibgeschützt. Es gibt keine sitzungsweite Genehmigungsoption. Verwende eine explizite `always_run`-Richtlinie nur, wenn eine Connector-Aktion unbeaufsichtigt ausgeführt werden muss.

<a id="connect-with-oauth"></a>

## Mit OAuth verbinden

### Projektseite „Connectors“ öffnen
Öffne das Projekt. Wähle **Connectors** und dann die App aus.

### Kontobereich auswählen
Wähle **Project** für ein gemeinsames Konto, auf das alle zugreifen können, denen der Connector gewährt wurde. Wähle **User** für ein privates Konto, das dir gehört und nur für dich zugänglich ist, und zwar nur in einer privaten Sitzung.

### Autorisierung abschließen
Schließe den OAuth-Ablauf ab. Beeuni speichert das verbundene Konto als Verbindung.

<a id="connect-an-mcp-server-that-uses-oauth-21"></a>

## Einen MCP-Server mit OAuth 2.1 verbinden

Beeuni implementiert die MCP-Autorisierungsspezifikation. Öffne den Connector, wähle **Add credential** und dann den Tab **OAuth 2.0**. Beeuni prüft den Server und liest dessen Metadaten aus:

1. Die nicht authentifizierte Prüfung gibt `401` mit `WWW-Authenticate: Bearer resource_metadata="…"` zurück.
2. Beeuni liest die Metadaten der geschützten Ressource (RFC 9728) unter dieser URL oder unter `/.well-known/oauth-protected-resource` aus.
3. Beeuni liest die Metadaten des Autorisierungsservers (RFC 8414 oder OpenID-Connect-Erkennung) für den ersten Autorisierungsserver aus, den die Ressource angibt.

Wenn dieser Server `registration_endpoint` bekannt gibt, registriert Beeuni sich als OAuth-Client (RFC 7591) und zeigt eine Schaltfläche an: **Connect &lt;server&gt;**. Du musst keine Anwendung erstellen und keine Client-ID oder kein Secret kopieren. Beeuni führt dann Authorization Code mit PKCE (S256) aus und bindet das Token über den Parameter `resource` (RFC 8707) an den Server.

Registriere diese Redirect-URI, wenn ein Server sie im Voraus benötigt:

```text
https://api.beeuni.ai/v1/connectors/oauth2/callback
```

Wenn der Server Endpunkte, aber kein `registration_endpoint` veröffentlicht, trägt Beeuni die Autorisierungs-URL, die Token-URL und die Scopes vorausgefüllt ein. Gib die Client-ID einer Anwendung ein, die du bei diesem Anbieter erstellst. Wenn der Server keine Metadaten veröffentlicht, gib alle Felder ein.

Beeuni hält die MCP-Sitzung aufrecht: Bei Bedarf führt es `initialize` und `notifications/initialized` aus und sendet bei späteren Aufrufen `Mcp-Session-Id`. Ein Server, der ohne Sitzung antwortet, bekommt den Handshake nie zu sehen.

Beeuni bindet jede Verbindung an den Autorisierungsserver, der sie ausgestellt hat. Wenn der Callback einen Parameter `iss` (RFC 9207) enthält, weist Beeuni ihn zurück, sofern er nicht mit dem gespeicherten Aussteller übereinstimmt – ein von einem anderen Server ausgestellter Code wird abgelehnt, bevor er eingelöst wird.

<a id="authorize-from-the-cli"></a>

### Über die CLI autorisieren

Das Dashboard ist eine Möglichkeit, diesen Ablauf auszuführen, aber nicht die einzige. Deklariere den Connector in `beeuni.yaml` und autorisiere ihn dann in einem Terminal oder einer Agent-Sitzung:

```yaml
connectors:
  - slug: read-ai
    name: Read AI
    provider: mcp
    url: 'https://api.read.ai/mcp'
    auth:
      type: bearer
```

```text
beeuni connectors authorize read-ai --json
```

Der Befehl erstellt die Verbindung, führt die Erkennungskette aus, registriert Beeuni als Client, wenn der Server RFC 7591 unterstützt, und gibt die URL zur Genehmigung zurück:

```json
{
  "connection_id": "7b1a16b2-...",
  "registered": true,
  "scopes": ["openid", "offline_access", "mcp:execute", "meeting:read"],
  "authorization_url": "https://authn.read.ai/oauth2/auth?response_type=code&...",
  "expires_at": "2026-08-19T14:48:26.345Z"
}
```

Ein Agent gibt `authorization_url` an die Person zurück, mit der er arbeitet. Nach der Genehmigung bestätigt der Agent:

```text
beeuni connectors authorize read-ai --status
```

Der Befehl wird mit einem von null verschiedenen Exit-Code beendet, solange der Status `error` lautet. Verwende `--scope`, um die angeforderten Berechtigungen einzugrenzen. Verwende `--client-id` und `--client-secret` für einen Server, der keine dynamische Clientregistrierung unterstützt.

Sobald die Autorisierung abgeschlossen ist, ruft Beeuni den Tool-Katalog des Connectors erneut ab. So verlässt der Connector den Status `error` ohne manuelle Synchronisierung.

<a id="connect-a-direct-api-with-oauth2"></a>

## Eine direkte API mit OAuth2 verbinden

Direkte Connectoren unterstützen:

- Client Credentials
- Authorization Code mit PKCE
- Geräteautorisierung
- dynamische Clientregistrierung (RFC 7591)

Gib für Client Credentials die Token-URL, die Client-ID, die Scopes und das Client-Secret ein. Du kannst `client_secret_basic`, `client_secret_post`, `client_secret_jwt` oder `private_key_jwt` zur Authentifizierung am Token-Endpunkt verwenden.

Gib für Authorization Code die Autorisierungs-URL und die Token-URL ein. Gib für die Geräteautorisierung die URL für die Geräteautorisierung und die Token-URL ein. Eine RFC-8414-Erkennungs-URL kann diese Endpunkte bereitstellen.

Beeuni verschlüsselt die OAuth2-Konfiguration und die Tokens. Es erneuert Zugriffstokens vor ihrem Ablauf und speichert jedes rotierte Refresh-Token. Wenn du die Verbindung widerrufst, wird der nächste Connector-Aufruf blockiert.

Verwende für Microsoft Graph:

```text
https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token
https://graph.microsoft.com/.default
```

Verwende für direkte SharePoint-REST-Aufrufe den SharePoint-Ressourcen-Scope:

```text
https://{tenant}.sharepoint.com/.default
```

<a id="connect-with-an-api-key"></a>

## Mit einem API-Schlüssel verbinden

### Connector deklarieren
```yaml
connectors:
- slug: stripe-read
name: Stripe read access
provider: openapi
spec: 'https://raw.githubusercontent.com/stripe/openapi/master/openapi/spec3.json'
auth:
type: bearer
policies:
- match: 'get_*'
action: always_run
- match: '*'
action: block
```

Das Manifest akzeptiert aus Gründen der Abwärtskompatibilität weiterhin einen Schlüssel `authorization_strategy`. Beeuni ignoriert ihn: Lege den Besitzer (gemeinsam oder privat) stattdessen pro Verbindung fest, wenn du die Anmeldedaten hinzufügst.

### Änderungsanfrage zusammenführen
Beeuni liest das Manifest aus dem Standardbranch. Der Connector wird aktiv, sobald die Änderungsanfrage zusammengeführt wurde.

### Verbindung hinzufügen
Öffne den Connector und lege seine Anmeldedaten fest. Beeuni speichert den Wert verschlüsselt. Der Wert wird nicht in das Manifest geschrieben.

<a id="grant-an-agent-access"></a>

## Einem Agent Zugriff gewähren

Füge den Connector-Slug zum Feld `connectors` des Agents hinzu:

```yaml
agents:
  release-bot:
    connectors: [stripe-read]
```

Lässt du `connectors` weg, erhält der Agent `none`. Führe die Änderung zusammen, bevor sie wirksam wird.

`connectors_required` ist veraltet. Das Manifest akzeptiert es weiterhin, aber es wird an keiner Stelle ausgelesen: Eine Sitzung wird beim Erstellen niemals abgelehnt, weil für einen Connector kein nutzbares Konto vorhanden ist. Eine Ablehnung beim Erstellen einer Sitzung wegen eines fehlenden Connectors war in der Praxis nicht erreichbar – für einen nur privaten Connector gab es kein gemeinsames Konto, das angeboten werden konnte, sodass die anfragende Person nichts gegen die Ablehnung unternehmen konnte. Die Prüfung erfolgt jetzt beim **Aufruf** des Connectors: Ein Agent mit Zugriff auf `stripe-read` kann seinen Turn sofort starten; abgelehnt wird nur ein Aufruf, der den Connector tatsächlich benötigt (siehe [Wenn ein Aufruf abgelehnt wird](#when-a-call-is-denied)) – mit einem Lösungsvorschlag.

<a id="select-an-account"></a>

## Konto auswählen

Es gibt zwei unabhängige Möglichkeiten, das Konto für einen Aufruf auszuwählen: eines für die gesamte Sitzung festlegen oder eines für einen einzelnen Aufruf angeben.

<a id="pin-a-session-wide-default"></a>

### Sitzungsweiten Standard festlegen

Eine Sitzung kann das Standardkonto des Connectors für alle Aufrufe überschreiben:

```json
{
  "connector_bindings": {
    "stripe-read": {
      "connection_id": "00000000-0000-4000-8000-000000000000"
    }
  }
}
```

Der Bindungsschlüssel ist der Connector-Slug. Der Wert ist ein Konto (eine Verbindung), auf das die aufrufende Person dieser Sitzung zugreifen darf.

Verwende `GET /projects/{projectId}/sessions/{sessionId}/scope`, um die effektive Bindung auszulesen. Verwende `PUT` für denselben Pfad, um sie zu ersetzen. Die Änderung gilt ab dem nächsten Tool-Aufruf, ohne dass die Sitzung neu gestartet werden muss.

<a id="name-an-account-on-one-call"></a>

### Konto für einen einzelnen Aufruf angeben

Liste die Konten auf, über die ein Connector aufgerufen werden kann – das Standardkonto zuerst – mit:

```text
GET /connectors/projects/{projectId}/connectors/{slug}/accounts
```

```json
{
  "connector": "stripe-read",
  "accounts": [
    { "connection_id": "...", "label": "Shared workspace", "owner_type": "project", "is_default": true, "connected_as": "billing@example.com" },
    { "connection_id": "...", "label": "My Stripe", "owner_type": "member", "is_default": false, "connected_as": null }
  ]
}
```

Nennen Sie dann ein Konto im Aufruf – anhand der Verbindungs-ID oder des Labels (ohne Beachtung der Groß-/Kleinschreibung) – oder mit den beiden Auswahlwörtern `me` (Ihr eigenes standardmäßiges privates Konto) und `project` (das standardmäßige gemeinsam genutzte Konto des Projekts):

```text
beeuni connectors call stripe-read get_balance '{}' --account me
beeuni connectors call stripe-read get_balance '{}' --account "Shared workspace"
```

Wird in einem Aufruf kein Konto angegeben, wird zuerst das eigene standardmäßige private Konto des Aufrufenden verwendet, danach das standardmäßige gemeinsam genutzte Konto des Projekts – unverändert gegenüber dem Verhalten, bevor ein Connector mehrere Konten haben konnte. Ein angegebenes Konto, das nicht aufgelöst werden kann, wird **abgelehnt** und niemals stillschweigend durch ein anderes ersetzt (siehe [Wann ein Aufruf abgelehnt wird](#when-a-call-is-denied)). Jedes erfolgreiche Aufrufergebnis gibt an, mit welchem Konto es ausgeführt wurde: `account: { connection_id, label,
owner_type }`.

<a id="use-a-connector-in-a-session"></a>

## Einen Connector in einer Sitzung verwenden

Verwenden Sie innerhalb einer Sitzung die Connector CLI:

```text
beeuni connectors ls
beeuni connectors accounts stripe-read
beeuni connectors call stripe-read <action> '<json-args>' [--account <id|label|me|project>]
```

`connectors` listet die Connectoren im Geltungsbereich auf. `accounts` listet die Konten auf, mit denen dieser Aufrufende `stripe-read` aufrufen darf – zuerst das Standardkonto, innerhalb jeder Gruppe gemeinsam genutzte Konten vor privaten. `call` führt eine Aktion aus, mit dem angegebenen `--account` oder, falls keines angegeben ist, mit derselben Standardauflösung wie zuvor, bevor ein Connector mehrere Konten haben konnte.

<a id="large-results"></a>

### Große Ergebnisse

Ein Listen- oder Suchaufruf kann mehr zurückgeben, als ein Modell lesen kann: Eine Toolausgabe über ~50 KB wird abgeschnitten. Speichern Sie das Ergebnis in einer Datei und verarbeiten Sie es mit Code:

```text
beeuni connectors call linear graphql.issues '{"first":250}' --out /workspace/output/issues.json
# → { "ok": true, "account": …, "saved_to": "/workspace/output/issues.json",
#     "bytes": 93037, "shape": { "issues": { "nodes": "array(250) of {id,title,…}",
#     "pageInfo": { "hasNextPage": true, "endCursor": "…" } } } }
jq '.data.issues.nodes[] | {id, title}' /workspace/output/issues.json
```

`--out` schreibt das vollständige JSON-Ergebnis und erstellt dabei übergeordnete Verzeichnisse. Stdout erhält den Aufruf-Umschlag ohne `data` sowie `saved_to`, `bytes` und `shape`: die Übersicht von `data` (Schlüssel, Array-Längen und jedes `pageInfo`). Der Exit-Code bleibt unverändert.

<a id="attach-files"></a>

### Dateien anhängen

Ein Aufruf enthält niemals Dateibytes in seinen Argumenten. Stellen Sie die Datei bereit und fügen Sie dann ihre Referenz in die Argumente ein. Das Gateway liest die Bytes serverseitig und schreibt sie in die Anfrage.

```text
beeuni connectors call microsoft-graph.sendmail @mail.json \
  --attach /workspace/artifacts/report.pdf
```

`--attach` stellt die Datei bereit und fügt eine Referenz zum Anlagen-Array der Aktion hinzu. Das Array ist im Eingabeschema der Aktion zu finden: `attachments` für den Email-Kanal, `body.message.attachments` für Microsoft Graph `sendMail`. Verwenden Sie `--attach-path body.message.attachments` als Namen, wenn das Schema ungewöhnlich ist.
Große JSON-Argumente gehören in eine Datei (`@mail.json`) oder auf stdin (`-`).

Wenn Sie eine Datei selbst einfügen möchten, stellen Sie sie zuerst bereit:

```text
beeuni connectors upload /workspace/artifacts/report.pdf --connector microsoft-graph
# → { "attachment_id": "…", "ref": { "$beeuni_attachment": "…" }, … }
```

Fügen Sie `ref` an beliebiger Stelle in die Argumente ein. Das Gateway ersetzt sie anhand ihrer Position:

| Position von `ref` | Ersetzt durch |
| --- | --- |
| Ein Element eines Anlagen-Arrays, dessen Elemente Objekte sind | Das Anlagenelement des Anbieters. Das Schema des Elements bestimmt die Form: Microsoft Graph `fileAttachment` (`name` + `contentBytes` oder `@odata.type`), Postmark (`Name` + `Content`), Mailjet (`Filename` + `Base64Content`), SendGrid und Resend (`filename` + `content`), Brevo (`name` + `content`). Jede andere Elementform wird mit `attachment_item_shape_unknown` abgelehnt. |
| Ein Zeichenfolgenfeld, z. B. `contentBytes` oder eine GitHub-Datei `content` | Die Base64-Darstellung der Datei. |
| `attachments[]` des Email-Kanals | Eine signierte Download-URL für den Email-Anbieter. |

Regeln:

- Dateien müssen aus `/workspace/output`, `/workspace/artifacts`,
  `/workspace/reports` oder `/workspace/deliverables` stammen. Symbolische Links und Hardlinks werden abgelehnt. Kopieren Sie die Datei zuerst dorthin.
- Ein Aufruf kann bis zu 20 Dateien mit insgesamt 25 MiB enthalten. Die Upstream-API kann ein niedrigeres Limit festlegen: Microsoft Graph gibt 3 MB als größte Datei an, die eine einzelne `sendMail`-Anfrage anhängen kann.
- Eine bereitgestellte Datei ist nur für die Sitzung verfügbar, in der sie bereitgestellt wurde, kann einmal verwendet werden und wird nach 24 Stunden gelöscht. Bei einem fehlgeschlagenen Aufruf kann sie erneut verwendet werden.
- Der Audit-Datensatz, die Genehmigungsvorschau und das Modell sehen nur die Referenz, niemals die Bytes. In einer Upstream-Fehlermeldung, die die Datei wiedergibt, wird die Base64-Darstellung entfernt.
- Verwaltete Connectoren akzeptieren keine bereitgestellten Dateien (`connector_attachments_unsupported`).

Der MCP-Server bietet denselben Ablauf: `call` nimmt `attachment_files` (und optional `attachment_path`) entgegen, und `upload_attachment` gibt ein `ref` zurück. Das SDK-Äquivalent lautet `connectors.uploadAttachment(bytes, { filename, contentType,
connector })`, which returns `ref`.

<a id="call-results"></a>

### Aufrufergebnisse

`POST /connectors/projects/{projectId}/call` gibt ein einzelnes JSON-Objekt zurück. Diese Felder sind bei allen Bindings identisch (OpenAPI, HTTP, MCP, GraphQL, `composio`, `pipedream`, Computer):

| Feld | Bei | Wert |
| --- | --- | --- |
| `data` | 200 | Die unveränderte rohe Upstream-Antwort. |
| `output` | 200 | Die Payload ohne den Umschlag des Bindings: `composio` `data.result`, MCP `result.structuredContent ?? result.content`, GraphQL `data.data`. Fehlt, wenn sie `data` entspricht (OpenAPI-, HTTP-, Postman-, Kanal-, `pipedream`- und Computeraufrufe), sodass der Body die Payload nur einmal enthält: Lesen Sie `output ?? data`. Das SDK ergänzt sie. |
| `binding` | 200, 500, 429, 503 | Das Binding, das den Aufruf ausgeführt hat: `openapi`, `http`, `mcp`, `graphql`, `composio`, `pipedream`, `pipedream_proxy`, `postman`, `tunnel`. `null` bei einem Fehler, bevor die Aktion aufgelöst wurde. |
| `upstream_status` | 200, 500, 429, 503 | Der Upstream-HTTP-Status. `null`, wenn kein Upstream geantwortet hat (bei einem Timeout, einer abgelehnten Anfrage oder einem Computer). `composio` und `pipedream` melden einen Anbieterfehler innerhalb einer 200-Antwort; dafür setzt Beeuni `502` (`400` bei einer abgelehnten Linear-Abfrage, `429` bei einer Ratenbegrenzung). |
| `upstream_error` | 200 | Wird angegeben, wenn der Upstream einen Fehler innerhalb einer 2xx-Antwort gemeldet hat: ein MCP-Toolergebnis mit `isError: true` oder einem JSON-RPC-Fehler oder GraphQL `errors` ohne Daten. Der Aufruf gilt dennoch als ausgeführt: `ok` bleibt `true`. |
| `retry_after_seconds` | 429, 503 | Das `Retry-After` des Upstreams in Sekunden, sofern eines mitgesendet wurde. Die Antwort enthält außerdem den `Retry-After`-Header. |

Der HTTP-Status eines fehlgeschlagenen Aufrufs:

- Ein Upstream-`429` antwortet mit `429`. Ein Upstream-`503` antwortet mit `503`. Warten Sie `retry_after_seconds` (oder warten Sie mit exponentiellem Backoff) und versuchen Sie es erneut.
- Andere Upstream-Fehler antworten mit `500`; die Ursache steht in `reason`.

- Eine Upstream-Antwort mit mehr als 64 MiB wird mit `500` und `reason: "upstream_response_too_large: …"` beantwortet. Beeuni beendet das Lesen am Limit. Fordern Sie eine kleinere Seite oder einen Filter an.
- Ein Upstream, der nicht innerhalb der Frist antwortet, wird mit `500` und `reason: "upstream_timeout: …"` beantwortet. Die Frist beträgt standardmäßig 60 Sekunden. Legen Sie für den Client ein höheres Timeout fest, damit das Gateway immer zuerst antwortet.

Ein Connector-Aufruf ist nicht idempotent. Beeuni dedupliziert wiederholte Aufrufe nicht. Nach `upstream_timeout` oder einem clientseitigen Abbruch kann der Aufruf beim Upstream ausgeführt worden sein: Prüfen Sie die Auswirkungen, bevor Sie einen Schreibvorgang wiederholen (etwa eine gesendete E-Mail oder einen erstellten Datensatz).

<a id="typed-calls-from-code"></a>

### Typisierte Aufrufe aus Code

`beeuni connectors types` schreibt für jede aufrufbare Aktion eine TypeScript-Deklarationsdatei. Jede Aktion erhält ihren Argumenttyp aus ihrem Eingabeschema und ihren Ergebnistyp aus ihrem Ausgabeschema. Der Ergebnistyp beschreibt das Feld `output` des Aufrufs.

```sh
beeuni connectors types --out src/beeuni-connectors.d.ts
beeuni connectors types --connector linear,github --out src/beeuni-connectors.d.ts
```

Binden Sie die Datei in Ihre `tsconfig.json` ein. Rufen Sie dann über `callAction` auf:

```ts
import { createBeeuni } from '@beeuni/sdk';

const connectors = createBeeuni({ backendUrl, getToken }).project(projectId).connectors;
const result = await connectors.callAction('linear', 'list_issues', { team: 'CORE' });
if (result.ok) console.log(result.output?.issues.length);
```

Der Connector-Handle liest dieselbe Datei, und `run` gibt die typisierte Ausgabe selbst zurück oder löst einen typisierten Fehler aus (siehe Connectoren aus Code):

```ts
const issues = await createBeeuni({ backendUrl, getToken })
  .project(projectId)
  .connector('linear')
  .run('list_issues', { team: 'CORE' });
```

`callAction(slug, action, args, options)` sendet dieselbe Anfrage wie `call('<slug>.<action>', args, options)` und gibt dasselbe Ergebnis zurück. Nur die Typen unterscheiden sich: Ein fehlendes oder unbekanntes Argument führt zu einem Kompilierungsfehler, und `output` hat den generierten Typ. Eine Aktion, die nicht in der Datei enthalten ist, akzeptiert ein beliebiges Objekt und gibt `output: unknown` zurück.

- OpenAPI-, HTTP-, MCP- und GraphQL-Connectoren veröffentlichen ein Ausgabeschema, wenn ihre Quelle eines deklariert. Das Ergebnis einer GraphQL-Abfrage wird als Objekt typisiert.
- Verwaltete Connectoren veröffentlichen kein Ausgabeschema. Ihr Ergebnis ist `unknown`. Die CLI benennt sie danach, wenn sie die Datei schreibt.
- Jeder `$defs`-Eintrag wird zu einem benannten Typ (`BeeuniConnectorDef<n>_<name>`), sodass ein rekursives Schema endlich bleibt. Ein Schema, das nicht kompiliert werden kann (eine Union, die sich selbst enthält), oder dessen Typen für eine Aktion 256 KB überschreiten, wird zu `unknown`.
- Führen Sie den Befehl erneut aus, nachdem Sie einen Connector hinzugefügt haben oder eine neue Version synchronisiert wurde.
- Der Katalog gibt Ausgabeschemas nur auf Anfrage zurück:
  `GET /connectors/projects/{projectId}/catalog?include_output_schemas=true`
  fügt jeder Aktion `outputSchema` hinzu (`null`, wenn keines gespeichert ist).

<a id="when-a-call-is-denied"></a>

### Wenn ein Aufruf abgelehnt wird

Ein abgelehnter Aufruf antwortet mit `{ ok: false, status: "denied", reason, hint }`. `reason` ist ein stabiler Code; `hint` gibt an, was zu tun ist.

| `reason` | HTTP | Bedeutung | Ebenfalls im Body |
| --- | --- | --- | --- |
| `connector_not_assigned` | 403 | Die `connectors:`-Berechtigung des laufenden Agenten in `beeuni.yaml` umfasst diesen Connector nicht. | `agent`, `granted` (die Liste oder `"all"`), `manifest_revision` und `manifest_commit` (das Manifest, aus dem die Berechtigung stammt). |
| `connector_not_connected` | 403 | Für diesen Aufruf ist kein nutzbares Konto vorhanden. Entweder hat der Connector für diesen Aufrufer überhaupt kein Konto (keine gespeicherten Zugangsdaten oder die App wurde nie autorisiert — `beeuni connectors ls` zeigt sie als `needs_auth`), oder `--account` hat eines angegeben, das nicht aufgelöst werden konnte. | `connect_url` — ein gehosteter Link zur Autorisierung eines Kontos, wenn der Aufrufer eines erstellen kann — wenn nichts verbunden ist. `requested_account` und `available_accounts` — der Name, der nicht aufgelöst werden konnte, und die Namen, die aufgelöst wurden — wenn `--account` eines angegeben hat. |
| `connector_disabled` | 403 | Der Connector ist deklariert, aber deaktiviert. | — |
| `connector_not_found` | 404 | Im Projekt ist kein Connector mit diesem Slug deklariert. | — |
| `action_not_found` | 404 | Der Connector verfügt über keine solche Aktion. | — |

`connect_url` ist die vollständige Abhilfe für einen nicht verbundenen Connector: Eine Sitzung wird für diesen niemals im Voraus abgelehnt (siehe [Einem Agenten Zugriff gewähren](#grant-an-agent-access)), daher enthält die Ablehnung selbst die Lösung. Der Agent zeigt den Link unverändert an; das Web-Transkript rendert ihn als Connect-Schaltfläche mit einem Klick. Der Link autorisiert standardmäßig ein privates Konto für die Person, die ihn öffnet — das Verbinden eines gemeinsam genutzten Kontos ist eine ausdrückliche Auswahl (`beeuni connectors connect stripe-read --owner project`, abhängig von `project.connector.write`).

Der Channel-Connector, der eine Sitzung erstellt hat (Slack, Teams, E-Mail), kann von dieser Sitzung aus immer aufgerufen werden, unabhängig davon, was die Berechtigung des Agenten besagt. So kann der Agent immer in dem Thread berichten, aus dem er angefordert wurde.

Die Berechtigung einer Sitzung folgt `beeuni.yaml`: Eine Änderung an der `connectors:` des laufenden Agenten (einschließlich `beeuni connectors add --apply`) wird beim nächsten Aufruf wirksam. Die Berechtigung vermerkt, aus welchem Manifest-Blob und welchem Commit sie stammt; ein Lesevorgang, der sie aus demselben Blob ersetzen würde, wird zuvor durch einen zweiten Lesevorgang bestätigt, und ein Lesevorgang aus einem älteren Commit ersetzt sie niemals.

Slack und Microsoft Teams werden über das Dashboard auf dieselbe Weise wie OAuth-Apps verbunden. Beim Verbinden von Slack wird für Sie ein `channel`-Connector in `beeuni.yaml` geschrieben. Siehe [Slack & Channels](/docs/de/connect/slack).
