Connector Development Guide
Version française : ../../fr/guides/connector-development.md
This guide shows how to write, validate, register, configure, test, synchronise, version and retire a connector to a
business system. It is for developers with the developer or tenant_admin role; storing credentials needs
tenant_admin or security_officer, and deleting a connector needs tenant_admin.
Concept
A connector is a manifest of kind Connector that declares a business system, its authentication, its resources and
their classification. The Control Plane stores the manifest; the Credential Broker keeps the credentials and hands
short leases to the runtime, so an agent never sees a secret. Every outbound call goes through the egress guard and
the connector.test or connector.sync policy. A connector is active or disabled.
Manifest fields
The manifest follows contracts/v1/connector-manifest.schema.json.
| Field | Type | Required | Description |
|---|---|---|---|
apiVersion, kind, metadata | yes | enterprise-ai.io/v1, Connector, name, version, owner. | |
spec.description | string | no | What the connector reads or writes. |
spec.system | string | yes | Kind of system, such as rest. |
spec.base_url | string | no | Base address, checked by the egress guard when saved. |
spec.auth | object | yes | type (oauth2, api_key, service_account, basic, mtls, none), authorization_url, token_url (required for oauth2), oauth_scopes, credential_ref, delegation (service, on_behalf_of_user). |
spec.scopes | array | no | Scopes the connector may lease. |
spec.resources | array | yes | Each item: name, operations (read, write, delete, subscribe), classification. |
spec.sync | object | no | mode (none, pull, push, cdc), schedule (cron), incremental. |
spec.webhooks | object | no | enabled, signature (hmac_sha256; none is refused), secret_ref (openbao:// or env://). |
spec.rate_limit | object | no | requests_per_minute. |
spec.data_residency | no | Region where the data must stay. |
Create a connector
The template sdks/python/src/enterprise_ai/templates/connector provides connector.py, connector.yaml (contracts/v1/connector-manifest.schema.json), policies and tests.
enterprise-ai create connector sharepoint
enterprise-ai validate -f sharepoint/connector.yaml
Steps
-
Create the project from the template. It writes the manifest, the code, an OPA policy with its tests and pytest tests. In the portal: Developer Studio > Connector studio > New.
enterprise-ai create connector sharepointExpected result: the files are listed and
connector.yamlis marked valid.If it fails: exit code 1 with "exists"; add
--forceor pick another name. -
Edit the manifest. Set the system,
base_url, the authentication and one entry per resource with its operations and classification. Write only a reference incredential_ref(openbao://...), never a value.Expected result: each resource the agents need is declared with the smallest set of operations.
If it fails: see the field table above.
-
Validate and test locally. The offline check reads the contract; the tests of the template run the policy and the code.
enterprise-ai validate -f sharepoint/connector.yamlcd sharepointpython -m pytest -q testsenterprise-ai test authzExpected result: exit code 0 everywhere.
If it fails: fix the fields or the rules listed.
-
Register the connector. POST /v1/connectors creates it, or updates it when the name exists. In the portal: Save as a new version.
enterprise-ai apply -f connector.yamlExpected result: status
createdorupdated.If it fails: 422
invalid_manifestwithauth.token_url(OAuth 2 without token address) orwebhooks.signature(unsigned webhooks), 403egress_deniedfor an address outside the egress policy. -
Store the credentials. POST /v1/connectors/{name}/credentials hands them to the Credential Broker; they are written once and never returned. The
kindfield selects the fields:oauth2_client(client_id,client_secret),oauth2_code(code,redirect_uri, optionalcode_verifier),api_key(api_key, optionalheader),service_account(private_keyortoken),basic(username,password),webhook_secret(secret).client.connectors.set_credentials("sharepoint", {"kind": "oauth2_client", "client_id": "<client-id>", "client_secret": "<secret>"})Expected result:
stored: truewith the list of stored field names.If it fails: 400
invalid_requestlists the missing fields or the allowed kinds; 409credential_unavailableforoauth2_codebeforeoauth2_client. -
Test the connection. POST /v1/connectors/{name}/test resolves the credentials and calls
base_urlthrough the egress guard. In the portal: Connector studio > connector > Test > Test the connection.Expected result:
ok: true,credentials: ok, thehttp_statusandlatency_ms.If it fails:
errorgives the cause:egress_denied,upstream_unavailable,credential_unavailableorcredential_rejected. -
Synchronise. POST /v1/connectors/{name}/sync queues a sync run (202) on the readable resources; an incremental sync resumes from the last cursor unless
fullis set. GET /v1/connectors/{name}/sync-runs lists the runs.client.connectors.sync("sharepoint", full=True)Expected result: a sync run in
queued, thenrunningandsucceeded.If it fails: 409
sync_disabled(sync.modeisnone), 409connector_disabled, 409sync_in_progress, 400invalid_requestfor a resource that is not readable. -
Publish a new version. Raise
metadata.versionand apply the manifest again; the stored credentials are kept.Expected result: status
updated.If it fails: test the connection again (step 6) after a change of
auth. -
Disable or delete. PATCH /v1/connectors/{name} with
status: disabledstops new leases and revokes the active ones; DELETE /v1/connectors/{name} also deletes the stored secrets.client.connectors.update("sharepoint", status="disabled")Expected result: status
disabled, or 204 on delete.If it fails: 404
connector_not_found.
Deleting a connector deletes its credentials from the secret store. Disable it first when you may need it again.
OAuth, API keys and secrets
Credentials (OAuth client secret, API key of a business service) are write only: POST /v1/connectors/{name}/credentials hands them to the Credential Broker and they are never returned nor exposed to agents. Generic secrets go through POST /v1/secrets.
client.connectors.set_credentials("sharepoint", {"kind": "oauth2_client", "client_id": "<client-id>", "client_secret": "<secret>"})
At run time the runtime asks POST /v1/credentials/broker/lease for a lease (30 to 3600 seconds) limited to scopes of the connector. Webhooks of a connector arrive on POST /v1/webhooks/{connector}, signed with HMAC-SHA256 and a timestamp within 5 minutes.
Test and sync
POST /v1/connectors creates the connector, POST /v1/connectors/{name}/test checks the connection, POST /v1/connectors/{name}/sync starts a sync.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
404 connector_not_found | Unknown name in the tenant. | Check with enterprise-ai get connectors. |
422 invalid_manifest | auth.token_url missing for oauth2, or webhooks.signature: none. | Add the token address; keep hmac_sha256. |
403 egress_denied | base_url, token_url or authorization_url is outside the egress policy. | Ask the administrator to allow the host. |
400 invalid_request | Unknown credential kind or missing fields. | Send the fields of the kind listed in step 5. |
502 credential_unavailable | No credential stored, or the secret reference cannot be resolved. | Store the credentials, check credential_ref. |
502 credential_rejected | The token endpoint refused the client. | Check the client id and secret with the system owner. |
409 sync_disabled, sync_in_progress, connector_disabled | Sync not configured, already running, or connector disabled. | Set sync.mode, wait for the run, or enable the connector. |
403 scope_not_allowed | The lease asks for a scope outside spec.scopes. | Add the scope to the manifest or ask for less. |
401 invalid_lease | The lease is expired or revoked. | Ask for a new lease. |
401 invalid_signature, webhook_replay | Webhook signature wrong or timestamp too old. | Sign with the stored webhook secret and the current time. |
Next steps
- MCP development guide to expose the connector as tools.
- Pack development guide for the connector of a pack.
- Policy development guide and API reference guide.