Platform
ScaiWave ScaiGrid ScaiCore ScaiBot ScaiDrive ScaiKey Models Tools & Services
Solutions
Organisations Developers Internet Service Providers Managed Service Providers AI-in-a-Box
Resources
Support Documentation Blog Downloads
Company
About Research Careers Investment Opportunities Contact
Log in

Register a cloud MCP server

You have a hosted MCP server — your own deployment or a third party's — and you want its tools to appear platform-wide in your tenant. This tutorial covers the registration, the scope decision, the credential model, the discovery cycle, and the rotation flow.

Roughly 15 minutes if you have the server URL and credential ready.

1. Decide the shape#

Settle these before any API calls:

  • Scope. Personal (only you use it) or tenant-shared (everyone in your tenant uses it under one credential)?
  • Auth. Single bearer token (bearer), multiple HTTP headers (api_key_header), or open (none)?
  • Transport. streamable_http unless you know the server is SSE-only.
  • User-id forwarding. Should the third party see internal user IDs (per-user rate limits, their own audit log)? Default off.
  • Consent tier. auto runs without confirmation, confirm prompts the agent's chat caller on each invocation, locked forbids invocation outside a manual UI flow.

2. Register a personal server with bearer auth#

bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
curl -X POST "$SCAIGRID_HOST/v1/modules/scailink/remote-servers" \
  -H "Authorization: Bearer $SCAIGRID_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Notion MCP",
    "endpoint_url": "https://mcp.notion.example.com/mcp",
    "auth_type": "bearer",
    "credentials": {"authorization": "ntn_..."},
    "is_tenant_shared": false,
    "transport": "streamable_http",
    "consent_tier": "auto"
  }'
python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import httpx, os

server = httpx.post(
    f"{os.environ['SCAIGRID_HOST']}/v1/modules/scailink/remote-servers",
    headers={"Authorization": f"Bearer {os.environ['SCAIGRID_API_KEY']}"},
    json={
        "name": "Acme Notion MCP",
        "endpoint_url": "https://mcp.notion.example.com/mcp",
        "auth_type": "bearer",
        "credentials": {"authorization": "ntn_..."},
        "is_tenant_shared": False,
        "transport": "streamable_http",
        "consent_tier": "auto",
    },
).json()["data"]
javascript
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
const res = await fetch(`${process.env.SCAIGRID_HOST}/v1/modules/scailink/remote-servers`, {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.SCAIGRID_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    name: "Acme Notion MCP",
    endpoint_url: "https://mcp.notion.example.com/mcp",
    auth_type: "bearer",
    credentials: { authorization: "ntn_..." },
    is_tenant_shared: false,
    transport: "streamable_http",
    consent_tier: "auto",
  }),
});
const { data: server } = await res.json();

Save server.id — every subsequent call targets it.

3. Multi-header auth (api_key_header)#

When a server needs both X-API-Key and X-Org-Id, register with auth_type: "api_key_header" and one credential field per outbound header:

bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
curl -X POST "$SCAIGRID_HOST/v1/modules/scailink/remote-servers" \
  -H "Authorization: Bearer $SCAIGRID_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Internal CRM MCP",
    "endpoint_url": "https://crm.internal.example.com/mcp",
    "auth_type": "api_key_header",
    "credentials": {
      "x-api-key": "ak_...",
      "x-org-id": "org_..."
    },
    "is_tenant_shared": true,
    "transport": "streamable_http"
  }'

Each field name maps to an outbound header verbatim (lowercased on send).

4. Tenant-shared registrations#

For a server that everyone in your tenant should use under one service account, set is_tenant_shared=true and supply credentials owned by your tenant. The caller needs scailink:remote.manage_tenant — tenant admins have it; regular users normally don't.

bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
curl -X POST "$SCAIGRID_HOST/v1/modules/scailink/remote-servers" \
  -H "Authorization: Bearer $SCAIGRID_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Shared GitHub MCP",
    "endpoint_url": "https://gh-mcp.example.com/mcp",
    "auth_type": "bearer",
    "credentials": {"authorization": "ghp_service_..."},
    "is_tenant_shared": true,
    "forward_user_id": true
  }'

forward_user_id: true adds X-ScaiGrid-User: <user_id> to outbound calls so the third party can attribute usage to your users — useful when you want their per-user rate-limiting to apply.

5. Confirm discovery succeeded#

bash
1
2
curl "$SCAIGRID_HOST/v1/modules/scailink/remote-servers/$SERVER_ID" \
  -H "Authorization: Bearer $SCAIGRID_API_KEY"

Look for:

  • status: "active" (not error).
  • last_health_status: "ok".
  • consecutive_failures: 0.
  • capabilities populated with the tools you expected.

If status is error, fix the upstream issue, then call refresh — you don't need to re-register.

6. On-demand refresh#

After a change on the server side (new tool added, schema updated), force a re-discovery instead of waiting for the 15-minute cron:

bash
1
2
curl -X POST "$SCAIGRID_HOST/v1/modules/scailink/remote-servers/$SERVER_ID/refresh" \
  -H "Authorization: Bearer $SCAIGRID_API_KEY"

The response is the same shape as GET /remote-servers/{id} — same capability rows, freshly upserted, with a recomputed health status.

7. Rotate a credential#

When upstream rotates the token, mirror it without re-registering:

bash
1
2
3
4
curl -X PUT "$SCAIGRID_HOST/v1/modules/scailink/remote-servers/$SERVER_ID/credentials/authorization" \
  -H "Authorization: Bearer $SCAIGRID_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"value": "ntn_new..."}'

The PUT is idempotent on (server, field) — it overwrites both ciphertext and DEK. The server's id and slug do not change; downstream namespaced tool names stay stable.

8. Watch for rotation reminders#

The detail response includes credential_oldest_days. The admin UI shows a warning at 90 days. Rotate proactively rather than reactively — upstream tokens that expire mid-cron cause consecutive_failures to climb and eventually trip the error status.

Done#

The server is registered, discovered, and visible in /mcp to everyone the scope and permissions allow. Iterate from here — add servers, scope them by group via custom roles, set consent_tier per-server, and let the cron do the rest.

Updated 2026-05-18 15:01:30 View source (.md) rev 12