@tideorg/mcp 1.4.0 → 1.4.2

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.
Files changed (80) hide show
  1. package/GAP_REGISTER.md +1 -1
  2. package/README.md +197 -38
  3. package/adapters/AGENTS.md +0 -0
  4. package/adapters/CLAUDE.md +0 -0
  5. package/adapters/replit.md +0 -0
  6. package/canon/anti-patterns.md +0 -0
  7. package/canon/concepts.md +0 -0
  8. package/canon/custom-contracts.md +0 -0
  9. package/canon/delegation.md +0 -0
  10. package/canon/feature-mapping.md +0 -0
  11. package/canon/framework-matrix.md +0 -0
  12. package/canon/invariants.md +0 -0
  13. package/canon/redirect-handler.md +0 -0
  14. package/canon/tidecloak-bootstrap.md +64 -0
  15. package/canon/tidecloak-endpoints.md +0 -0
  16. package/canon/troubleshooting.md +86 -0
  17. package/canon/version-policy.md +0 -0
  18. package/mcp-server/dist/http.d.ts +2 -0
  19. package/mcp-server/dist/http.js +46 -0
  20. package/mcp-server/dist/index.d.ts +0 -0
  21. package/mcp-server/dist/index.js +2 -601
  22. package/mcp-server/dist/server.d.ts +2 -0
  23. package/mcp-server/dist/server.js +415 -0
  24. package/package.json +1 -1
  25. package/playbooks/add-auth-nextjs-existing.md +0 -0
  26. package/playbooks/add-auth-nextjs-fresh.md +0 -0
  27. package/playbooks/add-rbac-nextjs.md +0 -0
  28. package/playbooks/bootstrap-realm-from-template.md +0 -0
  29. package/playbooks/configure-e2ee-roles-and-policies.md +0 -0
  30. package/playbooks/deploy-tidecloak-docker.md +0 -0
  31. package/playbooks/diagnose-broken-login.md +0 -0
  32. package/playbooks/diagnose-missing-roles-or-claims.md +0 -0
  33. package/playbooks/initialize-admin-and-link-account.md +0 -0
  34. package/playbooks/migrate-from-existing-auth.md +0 -0
  35. package/playbooks/protect-api-nextjs.md +0 -0
  36. package/playbooks/protect-routes-nextjs.md +0 -0
  37. package/playbooks/setup-forseti-e2ee.md +0 -0
  38. package/playbooks/setup-iga-admin-panel.md +0 -0
  39. package/playbooks/setup-server-delegation.md +0 -0
  40. package/playbooks/start-tidecloak-dev.md +0 -0
  41. package/playbooks/verify-jwt-server-side.md +0 -0
  42. package/prompts/add-admin-approval-flow.md +0 -0
  43. package/prompts/build-private-customer-portal.md +0 -0
  44. package/prompts/migrate-generic-auth-to-tide.md +0 -0
  45. package/prompts/secure-existing-app.md +0 -0
  46. package/reference-apps/INDEX.md +0 -0
  47. package/reference-apps/encrypted-communication/anti-patterns.md +0 -0
  48. package/reference-apps/encrypted-communication/bootstrap-sequence.md +0 -0
  49. package/reference-apps/encrypted-communication/manifest.yaml +0 -0
  50. package/reference-apps/encrypted-communication/role-policy-matrix.md +0 -0
  51. package/reference-apps/encrypted-communication/scenario.md +0 -0
  52. package/reference-apps/git-pr-signing-service/anti-patterns.md +0 -0
  53. package/reference-apps/git-pr-signing-service/bootstrap-sequence.md +0 -0
  54. package/reference-apps/git-pr-signing-service/manifest.yaml +0 -0
  55. package/reference-apps/git-pr-signing-service/role-policy-matrix.md +0 -0
  56. package/reference-apps/git-pr-signing-service/scenario.md +0 -0
  57. package/reference-apps/iga-admin-governance/anti-patterns.md +0 -0
  58. package/reference-apps/iga-admin-governance/bootstrap-sequence.md +0 -0
  59. package/reference-apps/iga-admin-governance/manifest.yaml +0 -0
  60. package/reference-apps/iga-admin-governance/role-policy-matrix.md +0 -0
  61. package/reference-apps/iga-admin-governance/scenario.md +0 -0
  62. package/reference-apps/organisation-password-manager/anti-patterns.md +0 -0
  63. package/reference-apps/organisation-password-manager/bootstrap-sequence.md +0 -0
  64. package/reference-apps/organisation-password-manager/manifest.yaml +0 -0
  65. package/reference-apps/organisation-password-manager/role-policy-matrix.md +0 -0
  66. package/reference-apps/organisation-password-manager/scenario.md +0 -0
  67. package/reference-apps/policy-governed-signing/anti-patterns.md +0 -0
  68. package/reference-apps/policy-governed-signing/bootstrap-sequence.md +0 -0
  69. package/reference-apps/policy-governed-signing/manifest.yaml +0 -0
  70. package/reference-apps/policy-governed-signing/role-policy-matrix.md +0 -0
  71. package/reference-apps/policy-governed-signing/scenario.md +0 -0
  72. package/skills/tide-diagnostics/SKILL.md +0 -0
  73. package/skills/tide-integration/SKILL.md +0 -0
  74. package/skills/tide-learning-capture/SKILL.md +0 -0
  75. package/skills/tide-rbac-and-e2ee/SKILL.md +0 -0
  76. package/skills/tide-reviewer/SKILL.md +0 -0
  77. package/skills/tide-route-and-api-protection/SKILL.md +0 -0
  78. package/skills/tide-scenario-resolver/SKILL.md +0 -0
  79. package/skills/tide-setup/SKILL.md +0 -0
  80. package/skills/tide-solutions-architect/SKILL.md +0 -0
package/GAP_REGISTER.md CHANGED
@@ -43,7 +43,7 @@ Controlled status set:
43
43
  | GAP-021 | Ragnarok post-transition details | STILL_UNRESOLVED | No exemplar implements Ragnarok. | Still needs transition plan. |
44
44
  | GAP-022 | C# SDK lacks Tide-specific content | PARTIALLY_RESOLVED_BY_MULTI_EXEMPLAR | Three contracts across two exemplars demonstrate comprehensive C# API surface: `IAccessPolicy`, `DataContext`, `ExecutorContext`, `ApproversContext`, `PolicyDecision`, `DokenDto`, `DokenDto.WrapAll()`, `Decision.*`, `TideKey.From()`, `Utils.GetEpochSeconds()`, `ExecutionType`, `ApprovalType`. | Not a standalone SDK package — types are available only within Forseti contract context. |
45
45
  | GAP-023 | Keycloak-to-TideCloak migration path | STILL_UNRESOLVED | No exemplar is a migration. All are greenfield. | Still needs migration guide. |
46
- | GAP-024 | Multi-tenant / multi-realm Fabric interaction | STILL_UNRESOLVED | All exemplars use single realm. tidewarden uses org-scoped roles (`org:{uuid}:role`) but still single realm. | Still needs multi-tenancy docs. |
46
+ | GAP-024 | Multi-tenant / multi-realm Fabric interaction | RESOLVED_BY_MULTI_EXEMPLAR | Ratidefy SaaS (ratidefy.com) implements full multi-tenant with per-tenant realms. Two-phase provisioning: realm+user first, role assignment after Tide account link. Path-based routing (`/t/<slug>/`). Each tenant gets independent VVK, Forseti policies, and IGA. Dynamic adapter config served from DB. Key learnings: client-origin-auth key format, IDP signing requirement, role assignment ordering. | Resolved. `canon/tidecloak-bootstrap.md` updated with "Hosted / SaaS Multi-Tenant Provisioning" section. |
47
47
  | GAP-025 | VVK ORK 12-gate verification details | STILL_UNRESOLVED | No exemplar reveals gate list. | Still needs full gate list and error behavior. |
48
48
  | GAP-026 | Adapter JSON field documentation | RESOLVED_BY_KEYLESSH | `tidecloakConfig.ts` TypeScript interface. forseti-crypto-quickstart provides additional field: `client-origin-auth-*` (signed origin binding). | Record as canon. Additional field `client-origin-auth-*` noted (GAP-048). |
49
49
  | GAP-027 | Production deployment guide | PARTIALLY_RESOLVED_BY_KEYLESSH | keylessh `DEPLOYMENT.md` shows container patterns. tidewarden shows Docker multi-stage builds + Dockerfile.acr for ACR. | Extract reusable patterns. Full checklist still needed. |
package/README.md CHANGED
@@ -1,38 +1,197 @@
1
- # Tide Agent Pack
2
-
3
- This repo turns Tide source material into operational assets for AI coding agents.
4
-
5
- ## Goal
6
-
7
- Help coding agents implement Tide correctly for low-experience builders.
8
-
9
- ## Primary outputs
10
-
11
- - canon doctrine
12
- - implementation playbooks
13
- - agent adapters
14
- - skills
15
- - starter prompts
16
- - starter templates
17
- - eval cases
18
-
19
- ## Source policy
20
-
21
- Put copied authoritative material in `sources/`.
22
- Do not rely on drifting live docs during drafting.
23
- Mark content as:
24
- - `VERIFIED`
25
- - `INFERRED`
26
- - `ASSUMED`
27
-
28
- ## Drafting order
29
-
30
- 1. `notes/source-audit.md`
31
- 2. `canon/*`
32
- 3. `playbooks/*`
33
- 4. `adapters/*`
34
- 5. `skills/*`
35
- 6. `prompts/*`
36
- 7. `templates/*`
37
- 8. `evals/cases.yaml`
38
- 9. `GAP_REGISTER.md`
1
+ # Tide Agent Pack
2
+
3
+ AI coding agents that know how to implement [TideCloak](https://tidecloak.com) correctly.
4
+
5
+ This MCP server gives your AI assistant deep knowledge of Tide authentication, threshold cryptography, Forseti smart contracts, and server-side security patterns. Instead of guessing, your AI follows verified playbooks.
6
+
7
+ ## Quick Start
8
+
9
+ ### Claude Code (CLI or VS Code extension)
10
+
11
+ Run this one command:
12
+
13
+ ```bash
14
+ claude mcp add tide-pack -- npx -y @tideorg/mcp
15
+ ```
16
+
17
+ Done. Start a conversation and ask your agent to add Tide auth to your app.
18
+
19
+ ### Project-level config (any MCP client)
20
+
21
+ Add a `.mcp.json` file to your project root:
22
+
23
+ ```json
24
+ {
25
+ "mcpServers": {
26
+ "tide-pack": {
27
+ "command": "npx",
28
+ "args": ["-y", "@tideorg/mcp"]
29
+ }
30
+ }
31
+ }
32
+ ```
33
+
34
+ Works with: Claude Code, Cursor, Windsurf, Cline, and any MCP-compatible tool.
35
+
36
+ ### Claude Desktop
37
+
38
+ Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
39
+
40
+ ```json
41
+ {
42
+ "mcpServers": {
43
+ "tide-pack": {
44
+ "command": "npx",
45
+ "args": ["-y", "@tideorg/mcp"]
46
+ }
47
+ }
48
+ }
49
+ ```
50
+
51
+ ### Cursor
52
+
53
+ Open Settings > MCP Servers > Add Server:
54
+ - Name: `tide-pack`
55
+ - Command: `npx`
56
+ - Args: `-y @tideorg/mcp`
57
+
58
+ Or add to `.cursor/mcp.json` in your project root.
59
+
60
+ ### Windsurf
61
+
62
+ Add to `~/.codeium/windsurf/mcp_config.json`:
63
+
64
+ ```json
65
+ {
66
+ "mcpServers": {
67
+ "tide": {
68
+ "url": "https://mcp.tide.org/mcp"
69
+ }
70
+ }
71
+ }
72
+ ```
73
+
74
+ Or for local: `"command": "npx", "args": ["-y", "@tideorg/mcp"]`
75
+
76
+ ### Zed
77
+
78
+ Add to your Zed settings (`~/.config/zed/settings.json`):
79
+
80
+ ```json
81
+ {
82
+ "context_servers": {
83
+ "tide": {
84
+ "command": {
85
+ "path": "npx",
86
+ "args": ["-y", "@tideorg/mcp"]
87
+ }
88
+ }
89
+ }
90
+ }
91
+ ```
92
+
93
+ Note: Zed uses `context_servers` (not `mcpServers`) and doesn't yet support remote URL-based MCP servers — use the npx command.
94
+
95
+ ### OpenAI Codex CLI
96
+
97
+ Add to `~/.codex/config.json`:
98
+
99
+ ```json
100
+ {
101
+ "mcpServers": {
102
+ "tide": {
103
+ "command": "npx",
104
+ "args": ["-y", "@tideorg/mcp"]
105
+ }
106
+ }
107
+ }
108
+ ```
109
+
110
+ Note: Codex CLI currently supports stdio-based MCP servers only — use the npx command.
111
+
112
+ ## What your AI can do with this
113
+
114
+ Once connected, your AI assistant can:
115
+
116
+ - **Add Tide auth** to a new or existing Next.js/React app
117
+ - **Protect API routes** with server-side JWT + DPoP verification
118
+ - **Set up role-based access** with Tide's IGA governance
119
+ - **Deploy Forseti smart contracts** for policy-governed encryption and signing
120
+ - **Bootstrap TideCloak** from Docker to fully configured realm
121
+ - **Diagnose issues** like broken login, missing roles, CORS errors
122
+ - **Follow security invariants** that prevent common auth mistakes
123
+
124
+ ## Try it
125
+
126
+ After setup, try these prompts in your AI coding tool:
127
+
128
+ > Add Tide authentication to my Next.js app
129
+
130
+ > I have an existing app with auth — help me migrate to Tide
131
+
132
+ > Set up encrypted data sharing between users with Tide
133
+
134
+ > Help me create a Forseti contract for multi-admin approval
135
+
136
+ ## What's inside
137
+
138
+ | Category | Count | Examples |
139
+ |----------|-------|---------|
140
+ | Canon doctrine | 12 files | Security invariants, anti-patterns, framework matrix, troubleshooting |
141
+ | Playbooks | 17 step-by-step guides | Add auth, protect APIs, verify JWTs, deploy TideCloak, set up E2EE |
142
+ | Skills | 9 composable roles | Setup, integration, security review, learning capture |
143
+ | Scenarios | 5 reference architectures | Password manager, signing service, encrypted chat, governance panel |
144
+ | Prompts | 4 starter prompts | Secure existing app, migrate auth, admin approval, customer portal |
145
+
146
+ ## Remote Server (no install required)
147
+
148
+ We host the MCP server so you don't have to install anything. Just add the URL:
149
+
150
+ ```json
151
+ {
152
+ "mcpServers": {
153
+ "tide": {
154
+ "url": "https://mcp.tide.org/mcp"
155
+ }
156
+ }
157
+ }
158
+ ```
159
+
160
+ No Node.js required. No npx. Works with any MCP client that supports remote servers.
161
+
162
+ ## Self-hosting
163
+
164
+ Want to run your own instance? Pull from Docker Hub:
165
+
166
+ ```bash
167
+ docker run -p 3000:3000 tideorg/mcp
168
+ ```
169
+
170
+ Or build from source:
171
+
172
+ ```bash
173
+ docker build -t tideorg/mcp .
174
+ docker run -p 3000:3000 tideorg/mcp
175
+ ```
176
+
177
+ Then point your MCP client at `http://localhost:3000/mcp`.
178
+
179
+ Optional: set `API_TOKEN` environment variable to require Bearer token auth:
180
+
181
+ ```bash
182
+ docker run -p 3000:3000 -e API_TOKEN=your-secret tideorg/mcp
183
+ ```
184
+
185
+ ## Requirements
186
+
187
+ - **Remote server**: None (just an MCP client that supports remote URLs)
188
+ - **npm/npx install**: Node.js 18+
189
+ - **Self-hosted Docker**: Docker
190
+
191
+ No TideCloak instance needed to start — the agent will guide you through setup.
192
+
193
+ ## Links
194
+
195
+ - [TideCloak](https://tidecloak.com) — The identity platform
196
+ - [npm package](https://www.npmjs.com/package/@tideorg/mcp) — `@tideorg/mcp`
197
+ - [Tide Foundation](https://tide.org) — The organisation behind Tide
File without changes
File without changes
File without changes
File without changes
package/canon/concepts.md CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -243,6 +243,70 @@ The bootstrap/init script must check the HTTP status of every critical step and
243
243
 
244
244
  ---
245
245
 
246
+ ## Hosted / SaaS Multi-Tenant Provisioning
247
+
248
+ When bootstrapping realms programmatically on a hosted TideCloak instance (e.g., `login.dauth.me`) for a multi-tenant SaaS application, the same initialization sequence applies but with critical differences. VERIFIED (Ratidefy SaaS, ratidefy.com).
249
+
250
+ ### Two-Phase Provisioning
251
+
252
+ Role assignment MUST happen after the admin user links their Tide account. IGA change requests require a Tide doken to be signable. Without a linked identity, the sign endpoint returns 200 but the change-set remains in DRAFT permanently.
253
+
254
+ **Phase A** (automated, before user interaction):
255
+ Steps 1–9 from the standard sequence, EXCEPT step 8c (role assignment). Generate the invite link at the end.
256
+
257
+ **Phase B** (after user links Tide account via invite link):
258
+ Step 8c (assign role) → Step 11 (approve role change-sets).
259
+
260
+ **Anti-pattern:** Assigning `tide-realm-admin` before the user links their Tide account. Creates an unsignable DRAFT change request. The only recovery is to delete the draft and re-assign after linking. VERIFIED.
261
+
262
+ ### client-origin-auth Key Format
263
+
264
+ The adapter config exported from TideCloak includes keys like:
265
+ ```
266
+ "client-origin-auth-https://myapp.example.com": "E1Kaff...=="
267
+ ```
268
+
269
+ The **origin URL is part of the key name**, not just metadata. When storing adapter config fields in a database for dynamic serving, preserve the full key name. Storing only the value produces invalid config that causes `[HEIMDALL] Client origin could not be verified`.
270
+
271
+ **Correct storage format** (e.g., JSON column):
272
+ ```json
273
+ { "key": "client-origin-auth-https://myapp.example.com", "value": "E1Kaff...==" }
274
+ ```
275
+
276
+ VERIFIED.
277
+
278
+ ### IDP Settings Signing
279
+
280
+ After setting `CustomAdminUIDomain` on the Tide IDP, you MUST call:
281
+ ```
282
+ POST /admin/realms/{realm}/vendorResources/sign-idp-settings
283
+ ```
284
+
285
+ Without this step, the Tide enclave rejects all signing/encryption requests from the configured origin with `Client origin could not be verified`. The sign step cryptographically binds the IDP settings to the ORK network. VERIFIED.
286
+
287
+ ### Path-Based vs Subdomain Tenant Routing
288
+
289
+ If using path-based routing (`myapp.com/t/<tenant>/`) instead of subdomains (`tenant.myapp.com`):
290
+ - Set redirect URIs on the **root domain** (`https://myapp.com/*`), not per-tenant subdomains
291
+ - `CustomAdminUIDomain` must be the root domain (`https://myapp.com`)
292
+ - The `client-origin-auth` key will reference the root domain
293
+
294
+ Subdomain routing requires a wildcard SSL certificate. Azure App Service managed certs do not support wildcards — use path-based routing or Azure Front Door. VERIFIED.
295
+
296
+ ### JWT kid Requirement
297
+
298
+ Some TideCloak realm configurations produce JWTs with missing `kid` (Key ID) in the header. The standard Keycloak admin REST API requires `kid` to verify token signatures. Tokens without `kid` cause 401 on all admin API calls even with valid roles.
299
+
300
+ **Symptom**: Token has all admin roles (`realm-admin`, `manage-users`, etc.) but admin API returns `{"error":"HTTP 401 Unauthorized"}`. TideCloak logs: `kid is null, cant find public key: realm={0}`.
301
+
302
+ **Fix**: Recreate the realm. The `kid` issue is a realm configuration problem, not a token issue. VERIFIED.
303
+
304
+ ### DPoP on Hosted Instances
305
+
306
+ DPoP (`useDPoP: { mode: 'strict', alg: 'EdDSA' }`) may not be supported on all hosted TideCloak instances. Enabling DPoP on `login.dauth.me` caused 500 on the token endpoint. Do not enable DPoP unless confirmed supported by the hosting provider. Standard `secureFetch` without DPoP works for admin API calls when the token has a valid `kid`. VERIFIED.
307
+
308
+ ---
309
+
246
310
  ## Data Directory Rules
247
311
 
248
312
  - Mount `./data:/opt/keycloak/data/h2`, never the project root.
File without changes
@@ -1492,3 +1492,89 @@ VERIFIED (TIDE_LEARNINGS-001 L-11).
1492
1492
  **Verification**: After fixing the server error, the request returns 200 with proper CORS headers.
1493
1493
 
1494
1494
  VERIFIED (LEARNINGS-ratidefy-batch-001 L-15).
1495
+
1496
+ ---
1497
+
1498
+ ## T-20: Admin API Returns 401 Despite Valid Roles (Missing JWT kid)
1499
+
1500
+ **Symptom**: Token has all admin roles (`realm-admin`, `manage-users`, `view-users`, etc.), token is not expired, but admin REST API returns `{"error":"HTTP 401 Unauthorized"}`. TideCloak logs show `kid is null, cant find public key: realm={0}`.
1501
+
1502
+ **Possible Causes**:
1503
+ 1. JWT header has no `kid` field — realm's EdDSA signing key configuration is broken
1504
+ 2. Token signed with ORK threshold EdDSA but no `kid` reference for admin API to look up the verification key
1505
+
1506
+ **Diagnostics**:
1507
+
1508
+ ```bash
1509
+ # Decode the JWT header
1510
+ echo '<token>' | cut -d. -f1 | base64 -d 2>/dev/null | jq .
1511
+ # If output shows {"alg":"EdDSA","typ":"JWT"} with NO "kid" field — that's the problem
1512
+ ```
1513
+
1514
+ **Fix**: Recreate the TideCloak realm. The `kid` issue is a realm-level configuration problem that cannot be fixed on existing tokens. A new realm will issue tokens with proper `kid` in the JWT header.
1515
+
1516
+ **Verification**: After recreating the realm, decode a new token's header — it should include `"kid": "some-key-id"`.
1517
+
1518
+ VERIFIED (Ratidefy SaaS — ratidefy-sign realm had missing kid, recreated as ratidefy-sign-2).
1519
+
1520
+ ---
1521
+
1522
+ ## T-21: Enclave Error "Client origin could not be verified"
1523
+
1524
+ **Symptom**: Tide enclave popup appears and immediately closes. Browser console shows `[HEIMDALL] Recieved enclave error: Client origin could not be verified`.
1525
+
1526
+ **Possible Causes**:
1527
+ 1. `CustomAdminUIDomain` not set on Tide IDP
1528
+ 2. IDP settings not signed after setting `CustomAdminUIDomain`
1529
+ 3. `client-origin-auth` key in adapter config is malformed or missing the origin URL
1530
+
1531
+ **Diagnostics**:
1532
+
1533
+ ```bash
1534
+ # Check CustomAdminUIDomain
1535
+ TOKEN=$(curl -s -X POST "$TC_URL/realms/master/protocol/openid-connect/token" \
1536
+ -d "username=admin&password=$PASS&grant_type=password&client_id=admin-cli" | jq -r .access_token)
1537
+ curl -s "$TC_URL/admin/realms/$REALM/identity-provider/instances/tide" \
1538
+ -H "Authorization: Bearer $TOKEN" | jq '.config.CustomAdminUIDomain'
1539
+
1540
+ # Check adapter config for client-origin-auth key
1541
+ # The key MUST include the origin URL: "client-origin-auth-https://myapp.com"
1542
+ # NOT a hash/signature as the key suffix
1543
+ ```
1544
+
1545
+ **Fix**:
1546
+ 1. Set `CustomAdminUIDomain` to the app origin (e.g., `https://myapp.com`)
1547
+ 2. Sign the IDP settings: `POST /admin/realms/{realm}/vendorResources/sign-idp-settings`
1548
+ 3. Ensure adapter config `client-origin-auth` key includes the origin URL, not just the signature value
1549
+
1550
+ **Verification**: Enclave popup appears and stays open for user interaction.
1551
+
1552
+ VERIFIED (Ratidefy SaaS — IDP settings unsigned, client-origin-auth key had signature instead of origin URL).
1553
+
1554
+ ---
1555
+
1556
+ ## T-22: IGA Role Assignment Stuck in DRAFT (Unsignable Change Request)
1557
+
1558
+ **Symptom**: Role assigned to user via admin API, change request created, but sign/commit returns 200 without actually signing. Role remains in DRAFT state permanently.
1559
+
1560
+ **Possible Causes**:
1561
+ 1. Role assigned before the user linked their Tide account — IGA requires a Tide doken for change request signing
1562
+ 2. The master admin token can create change requests but cannot sign them without a Tide identity
1563
+
1564
+ **Diagnostics**:
1565
+ 1. Check TideCloak admin → realm → Users → target user → Role Mapping tab
1566
+ 2. If role shows "DRAFT" badge, the change request was never signed
1567
+ 3. Check if user has a federated identity (Identity Provider Links tab)
1568
+
1569
+ **Fix**:
1570
+ 1. Delete the DRAFT change request
1571
+ 2. Ensure the user links their Tide account first (via invite link)
1572
+ 3. Then assign the role — the change request can now be signed
1573
+
1574
+ **Prevention**: In automated provisioning, split into two phases:
1575
+ - Phase A: Create realm, user, generate invite link (no role assignment)
1576
+ - Phase B: After user links Tide account, assign role and approve change request
1577
+
1578
+ **Verification**: Role shows "ACTIVE" status in TideCloak admin after sign+commit.
1579
+
1580
+ VERIFIED (Ratidefy SaaS — provisioner assigned tide-realm-admin before account linking, creating permanent DRAFT).
File without changes
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env node
2
+ import express from "express";
3
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
4
+ import { createServer } from "./server.js";
5
+ const app = express();
6
+ app.use(express.json());
7
+ // Optional Bearer token auth
8
+ const API_TOKEN = process.env.API_TOKEN;
9
+ if (API_TOKEN) {
10
+ app.use("/mcp", (req, res, next) => {
11
+ const auth = req.headers.authorization;
12
+ if (!auth || auth !== `Bearer ${API_TOKEN}`) {
13
+ res.status(401).json({ error: "Unauthorized" });
14
+ return;
15
+ }
16
+ next();
17
+ });
18
+ }
19
+ // MCP endpoint — stateless (new server + transport per request)
20
+ app.post("/mcp", async (req, res) => {
21
+ const server = createServer();
22
+ const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
23
+ res.on("close", () => {
24
+ transport.close();
25
+ server.close();
26
+ });
27
+ await server.connect(transport);
28
+ await transport.handleRequest(req, res, req.body);
29
+ });
30
+ // Handle GET and DELETE for SSE streams (required by protocol)
31
+ app.get("/mcp", async (req, res) => {
32
+ res.status(405).json({ error: "Method not allowed. Use POST for stateless MCP." });
33
+ });
34
+ app.delete("/mcp", async (req, res) => {
35
+ res.status(405).json({ error: "Method not allowed. Stateless server — no sessions to delete." });
36
+ });
37
+ // Health check for Azure / load balancers
38
+ app.get("/health", (_, res) => {
39
+ res.status(200).json({ status: "ok", name: "@tideorg/mcp" });
40
+ });
41
+ const port = parseInt(process.env.PORT || "3000", 10);
42
+ app.listen(port, "0.0.0.0", () => {
43
+ console.log(`@tideorg/mcp HTTP server listening on port ${port}`);
44
+ console.log(`MCP endpoint: http://0.0.0.0:${port}/mcp`);
45
+ console.log(`Health check: http://0.0.0.0:${port}/health`);
46
+ });
File without changes