curl --request POST \
--url https://api.openworklabs.com/v1/mcp-connections \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"kind": "native_provider",
"nativeProviderKey": "<string>",
"name": "<string>",
"oauthClient": {
"clientId": "<string>",
"clientSecret": "<string>",
"features": [
"<string>"
]
}
}
'import requests
url = "https://api.openworklabs.com/v1/mcp-connections"
payload = {
"kind": "native_provider",
"nativeProviderKey": "<string>",
"name": "<string>",
"oauthClient": {
"clientId": "<string>",
"clientSecret": "<string>",
"features": ["<string>"]
}
}
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
kind: 'native_provider',
nativeProviderKey: '<string>',
name: '<string>',
oauthClient: {clientId: '<string>', clientSecret: '<string>', features: ['<string>']}
})
};
fetch('https://api.openworklabs.com/v1/mcp-connections', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.openworklabs.com/v1/mcp-connections",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'kind' => 'native_provider',
'nativeProviderKey' => '<string>',
'name' => '<string>',
'oauthClient' => [
'clientId' => '<string>',
'clientSecret' => '<string>',
'features' => [
'<string>'
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.openworklabs.com/v1/mcp-connections"
payload := strings.NewReader("{\n \"kind\": \"native_provider\",\n \"nativeProviderKey\": \"<string>\",\n \"name\": \"<string>\",\n \"oauthClient\": {\n \"clientId\": \"<string>\",\n \"clientSecret\": \"<string>\",\n \"features\": [\n \"<string>\"\n ]\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.openworklabs.com/v1/mcp-connections")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"kind\": \"native_provider\",\n \"nativeProviderKey\": \"<string>\",\n \"name\": \"<string>\",\n \"oauthClient\": {\n \"clientId\": \"<string>\",\n \"clientSecret\": \"<string>\",\n \"features\": [\n \"<string>\"\n ]\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.openworklabs.com/v1/mcp-connections")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"kind\": \"native_provider\",\n \"nativeProviderKey\": \"<string>\",\n \"name\": \"<string>\",\n \"oauthClient\": {\n \"clientId\": \"<string>\",\n \"clientSecret\": \"<string>\",\n \"features\": [\n \"<string>\"\n ]\n }\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"name": "<string>",
"externalKey": "<string>",
"url": "<string>",
"authType": "oauth",
"credentialMode": "shared",
"apiKeyAuthScheme": "bearer",
"exposeDirectly": true,
"connected": true,
"connectedAt": "2023-11-07T05:31:56Z",
"connectedForMe": true,
"requiredBy": [
{
"pluginId": "<string>",
"name": "<string>"
}
],
"access": {
"orgWide": true,
"memberIds": [
"<string>"
],
"teamIds": [
"<string>"
]
},
"links": {
"yourConnections": "<string>",
"signIn": "<string>",
"oauthCallback": "<string>"
},
"readiness": {
"status": "ready",
"checkedAt": "2023-11-07T05:31:56Z",
"lastSuccessfulAt": "2023-11-07T05:31:56Z",
"reason": "<string>",
"failure": "sign_in_required"
},
"organizationReadiness": {
"status": "ready",
"checkedAt": "2023-11-07T05:31:56Z",
"lastSuccessfulAt": "2023-11-07T05:31:56Z",
"reason": "<string>",
"failure": "sign_in_required"
},
"mcpUrl": "<string>",
"createdByName": "<string>",
"createdByYou": true,
"canRemove": true,
"createdAt": "2023-11-07T05:31:56Z",
"updatedAt": "2023-11-07T05:31:56Z",
"needsReconnect": true,
"credentialHealth": "unknown",
"credentialHealthReason": "authorization_rejected",
"credentialHealthCheckedAt": "2023-11-07T05:31:56Z",
"issuerReviewRequired": true,
"reconnectActionOwner": "member",
"missingFeatures": [
"<string>"
],
"externalAccountId": "<string>",
"grantedScopes": [
"<string>"
],
"tenantId": "<string>",
"identityManagedBy": [
{
"pluginId": "<string>",
"name": "<string>"
}
],
"requiredAuthType": "oauth",
"authPolicyConfirmed": true,
"authTypeMismatch": true,
"oauthClientConfigured": true,
"oauthClientRequired": true,
"setupRequired": true,
"oauthClientId": "<string>",
"oauthClientHasSecret": true,
"manualOAuthEndpoints": {
"authorizationEndpoint": "<string>",
"tokenEndpoint": "<string>"
},
"oauthCallbackUrl": "<string>",
"oauthSharedCallbackUrl": "<string>",
"oauthClientMetadataUrl": "<string>",
"oauthCallbackMode": "shared-v1",
"oauthRegistrationSource": "pre-registered",
"authorizationServerIssuer": "<string>",
"requestedScopes": [
"<string>"
],
"credentialPrompt": {
"schemaVersion": "1",
"kind": "credential_prompt",
"target": {
"type": "mcp_connection_key",
"connectionId": "<string>"
},
"name": "<string>",
"destination": "<string>"
},
"nextStep": "<string>"
}{
"error": "invalid_request",
"details": [
{
"message": "<string>",
"path": [
"<string>"
]
}
],
"message": "<string>",
"capability": "<string>"
}{
"error": "unauthorized"
}{
"error": "forbidden",
"reason": "<string>",
"message": "<string>"
}{
"error": "external_key_exists",
"message": "<string>"
}{
"error": "connection_validation_failed",
"message": "<string>",
"diagnostic": {
"referenceId": "<string>",
"phase": "CONFIGURATION",
"category": "<string>",
"code": "<string>",
"highestPassed": "configured",
"retryable": true,
"actionOwner": "openwork",
"operatorAction": "<string>",
"message": "<string>",
"httpStatus": 349,
"operationPhase": "CONFIGURATION",
"outbound": {
"origin": "<string>",
"pathHash": "<string>"
},
"providerRequestId": "<string>",
"providerStatus": 0,
"providerCode": "<string>",
"payloadBytes": 0,
"jsonRpcCode": 0,
"connectUrl": "<string>"
}
}Register a new External MCP Connection for the org
Owners and admins can register any server. Other members can add one for themselves: an OAuth server where each person signs in (credentialMode per_member) or a server with no sign-in, shared with specific members or teams but never org-wide; the caller is always kept in its access. Registers a third-party MCP server by name + URL and grants access (org-wide, teams, or members). Use GET /v1/mcp-connections/presets for known server URLs (Notion, Linear, Stripe, Sentry, Slack, Context7). For credentialMode per_member, each member connects their own account afterwards — give the user links.signIn (a one-click browser sign-in page for this connection) when you cannot show a sign-in card, and share links.yourConnections so teammates know where to sign in. For servers with pre-registered OAuth apps, whitelist links.oauthCallback. API-key and OAuth-client credentials cannot be created through the agent surface; use the dashboard.
curl --request POST \
--url https://api.openworklabs.com/v1/mcp-connections \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"kind": "native_provider",
"nativeProviderKey": "<string>",
"name": "<string>",
"oauthClient": {
"clientId": "<string>",
"clientSecret": "<string>",
"features": [
"<string>"
]
}
}
'import requests
url = "https://api.openworklabs.com/v1/mcp-connections"
payload = {
"kind": "native_provider",
"nativeProviderKey": "<string>",
"name": "<string>",
"oauthClient": {
"clientId": "<string>",
"clientSecret": "<string>",
"features": ["<string>"]
}
}
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
kind: 'native_provider',
nativeProviderKey: '<string>',
name: '<string>',
oauthClient: {clientId: '<string>', clientSecret: '<string>', features: ['<string>']}
})
};
fetch('https://api.openworklabs.com/v1/mcp-connections', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.openworklabs.com/v1/mcp-connections",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'kind' => 'native_provider',
'nativeProviderKey' => '<string>',
'name' => '<string>',
'oauthClient' => [
'clientId' => '<string>',
'clientSecret' => '<string>',
'features' => [
'<string>'
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.openworklabs.com/v1/mcp-connections"
payload := strings.NewReader("{\n \"kind\": \"native_provider\",\n \"nativeProviderKey\": \"<string>\",\n \"name\": \"<string>\",\n \"oauthClient\": {\n \"clientId\": \"<string>\",\n \"clientSecret\": \"<string>\",\n \"features\": [\n \"<string>\"\n ]\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.openworklabs.com/v1/mcp-connections")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"kind\": \"native_provider\",\n \"nativeProviderKey\": \"<string>\",\n \"name\": \"<string>\",\n \"oauthClient\": {\n \"clientId\": \"<string>\",\n \"clientSecret\": \"<string>\",\n \"features\": [\n \"<string>\"\n ]\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.openworklabs.com/v1/mcp-connections")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"kind\": \"native_provider\",\n \"nativeProviderKey\": \"<string>\",\n \"name\": \"<string>\",\n \"oauthClient\": {\n \"clientId\": \"<string>\",\n \"clientSecret\": \"<string>\",\n \"features\": [\n \"<string>\"\n ]\n }\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"name": "<string>",
"externalKey": "<string>",
"url": "<string>",
"authType": "oauth",
"credentialMode": "shared",
"apiKeyAuthScheme": "bearer",
"exposeDirectly": true,
"connected": true,
"connectedAt": "2023-11-07T05:31:56Z",
"connectedForMe": true,
"requiredBy": [
{
"pluginId": "<string>",
"name": "<string>"
}
],
"access": {
"orgWide": true,
"memberIds": [
"<string>"
],
"teamIds": [
"<string>"
]
},
"links": {
"yourConnections": "<string>",
"signIn": "<string>",
"oauthCallback": "<string>"
},
"readiness": {
"status": "ready",
"checkedAt": "2023-11-07T05:31:56Z",
"lastSuccessfulAt": "2023-11-07T05:31:56Z",
"reason": "<string>",
"failure": "sign_in_required"
},
"organizationReadiness": {
"status": "ready",
"checkedAt": "2023-11-07T05:31:56Z",
"lastSuccessfulAt": "2023-11-07T05:31:56Z",
"reason": "<string>",
"failure": "sign_in_required"
},
"mcpUrl": "<string>",
"createdByName": "<string>",
"createdByYou": true,
"canRemove": true,
"createdAt": "2023-11-07T05:31:56Z",
"updatedAt": "2023-11-07T05:31:56Z",
"needsReconnect": true,
"credentialHealth": "unknown",
"credentialHealthReason": "authorization_rejected",
"credentialHealthCheckedAt": "2023-11-07T05:31:56Z",
"issuerReviewRequired": true,
"reconnectActionOwner": "member",
"missingFeatures": [
"<string>"
],
"externalAccountId": "<string>",
"grantedScopes": [
"<string>"
],
"tenantId": "<string>",
"identityManagedBy": [
{
"pluginId": "<string>",
"name": "<string>"
}
],
"requiredAuthType": "oauth",
"authPolicyConfirmed": true,
"authTypeMismatch": true,
"oauthClientConfigured": true,
"oauthClientRequired": true,
"setupRequired": true,
"oauthClientId": "<string>",
"oauthClientHasSecret": true,
"manualOAuthEndpoints": {
"authorizationEndpoint": "<string>",
"tokenEndpoint": "<string>"
},
"oauthCallbackUrl": "<string>",
"oauthSharedCallbackUrl": "<string>",
"oauthClientMetadataUrl": "<string>",
"oauthCallbackMode": "shared-v1",
"oauthRegistrationSource": "pre-registered",
"authorizationServerIssuer": "<string>",
"requestedScopes": [
"<string>"
],
"credentialPrompt": {
"schemaVersion": "1",
"kind": "credential_prompt",
"target": {
"type": "mcp_connection_key",
"connectionId": "<string>"
},
"name": "<string>",
"destination": "<string>"
},
"nextStep": "<string>"
}{
"error": "invalid_request",
"details": [
{
"message": "<string>",
"path": [
"<string>"
]
}
],
"message": "<string>",
"capability": "<string>"
}{
"error": "unauthorized"
}{
"error": "forbidden",
"reason": "<string>",
"message": "<string>"
}{
"error": "external_key_exists",
"message": "<string>"
}{
"error": "connection_validation_failed",
"message": "<string>",
"diagnostic": {
"referenceId": "<string>",
"phase": "CONFIGURATION",
"category": "<string>",
"code": "<string>",
"highestPassed": "configured",
"retryable": true,
"actionOwner": "openwork",
"operatorAction": "<string>",
"message": "<string>",
"httpStatus": 349,
"operationPhase": "CONFIGURATION",
"outbound": {
"origin": "<string>",
"pathHash": "<string>"
},
"providerRequestId": "<string>",
"providerStatus": 0,
"providerCode": "<string>",
"payloadBytes": 0,
"jsonRpcCode": 0,
"connectUrl": "<string>"
}
}Authorizations
Organization API key passed as the x-api-key header. The raw key is the header value; do not prefix it with Bearer.
Body
Response
Connection created.
oauth, apikey, none shared, per_member bearer, token ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
The calling member's own last check. Null means never checked for them (or the settings or their sign-in changed since).
Show child attributes
Show child attributes
scope=manageable only. Whether the connector itself works: for shared connections the shared credential's check; for per-member connections the latest Ready check any member recorded for the current settings, otherwise the caller's own check. Null means nobody has checked it yet.
Show child attributes
Show child attributes
^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$unknown, ready, reconnect_required authorization_rejected, credential_expired, post_authorization_validation_failed ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$member, organization_admin Show child attributes
Show child attributes
oauth, apikey, none Whether a client secret is configured. Only returned with explicit connection-settings view permission; never the secret itself.
Only returned with explicit connection-settings view permission; omitted from usable member listings, including for the connection creator.
Show child attributes
Show child attributes
shared-v1, isolated-v1, legacy-v1 pre-registered, client-metadata, dynamic Show child attributes
Show child attributes
Was this page helpful?