Skip to content

Commit d554f1d

Browse files
committed
feat: MCP SDK client, PKCE fix, attribute persistence, skills assignment UI, registry browsing
- Add MCP SDK client helper (mcp-client.ts) using @modelcontextprotocol/sdk - Refactor mcp-servers health check and tools to use SDK client - Fix PKCE double-login: detect OAuth callback in authStore.initialize() - Fix Keycloak attribute reading (string vs array) with getAttr() helper - Add MCP/skills attribute persistence in all SMART app CRUD handlers - Add client_type=agent filter so AI agents appear in SMART apps list - Extract shared AssignAppsDialog component for MCP/skills assignment - Add skills assignment UI to Skills tab with badges - Add MCP registry browsing, consent monitoring, FHIR monitoring routes - Add skills.sh client, runtime config, consent/IAL settings UI - Gate console.logs behind import.meta.env.DEV - Remove deprecated Fly.io configs [skip northflank]
1 parent c4a124a commit d554f1d

100 files changed

Lines changed: 12824 additions & 624 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# ╔═══════════════════════════════════════════════════════════╗
2+
# ║ Proxy Smart — Environment Variables ║
3+
# ╚═══════════════════════════════════════════════════════════╝
4+
# Copy this file to .env and fill in the values for your environment.
5+
6+
# ── Core ──────────────────────────────────────────────────
7+
NODE_ENV=development # development | production
8+
PORT=8445 # HTTP listen port
9+
BASE_URL=http://localhost:8445
10+
11+
# ── CORS ──────────────────────────────────────────────────
12+
# Comma-separated list of allowed origins.
13+
# In development mode, localhost origins are allowed by default.
14+
# In production, only these origins (or BASE_URL) are permitted.
15+
# CORS_ORIGINS=https://app.example.com,https://admin.example.com
16+
17+
# ── Keycloak / Auth ──────────────────────────────────────
18+
KEYCLOAK_BASE_URL=http://localhost:8080
19+
KEYCLOAK_REALM=proxy-smart
20+
# KEYCLOAK_DOMAIN= # Public hostname (if different from KEYCLOAK_BASE_URL)
21+
# KEYCLOAK_ADMIN_CLIENT_ID=admin-service
22+
# KEYCLOAK_ADMIN_CLIENT_SECRET= # Required in production
23+
24+
# Dev-only: set both to bypass admin role checks (never in production)
25+
# ALLOW_DEV_AUTH_BYPASS=true
26+
27+
# ── FHIR ─────────────────────────────────────────────────
28+
FHIR_SERVER_BASE=http://localhost:8081/fhir
29+
# FHIR_SUPPORTED_VERSIONS=R4 # Comma-separated: R4,R5
30+
31+
# ── SMART on FHIR ───────────────────────────────────────
32+
# SMART_CONFIG_CACHE_TTL=300000 # ms (default 5 min)
33+
# SMART_SCOPES_SUPPORTED= # Comma-separated override
34+
# SMART_CAPABILITIES= # Comma-separated override
35+
36+
# ── AI Assistant ─────────────────────────────────────────
37+
# OPENAI_API_KEY= # Enables built-in AI assistant
38+
# AI_TIMEOUT_MS=30000 # Request timeout for AI calls
39+
40+
# ── Consent & IAL ────────────────────────────────────────
41+
# Managed via Admin UI → Consent & IAL tab (persisted in Keycloak).
42+
# Env vars below serve as initial defaults before first admin save.
43+
# CONSENT_ENABLED=false
44+
# CONSENT_MODE=disabled # enforce | audit-only | disabled
45+
# IAL_ENABLED=false
46+
47+
# ── Kisi (Physical Access Control) ──────────────────────
48+
# KISI_API_KEY=
49+
# KISI_BASE_URL=https://api.kisi.io
50+
# KISI_TIMEOUT_MS=10000
51+
52+
# ── UniFi Access (Physical Access Control) ──────────────
53+
# UNIFI_ACCESS_HOST=
54+
# UNIFI_ACCESS_USERNAME=
55+
# UNIFI_ACCESS_PASSWORD=
56+
57+
# ── Docker ───────────────────────────────────────────────
58+
# DOCKER=true # Set automatically in containers

.github/instructions/instructions.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@ Never write fetch functions in the frontend, always generate from openapi backen
44

55
check in package.json how to generate client apis in doubt
66

7-
follow the concept of DRY! and use existing code patterns
7+
follow the concept of DRY! and use existing code patterns
8+
9+
mind that we use ui\src\i18n\translations

.github/workflows/ai-build-test-backend.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ jobs:
255255
run: |
256256
echo "Running backend tests..."
257257
cd backend
258-
# bun test 2>&1 | tee ../backend-test.log
258+
bun test 2>&1 | tee ../backend-test.log
259259
260260
- name: Check Test Results
261261
if: ${{ inputs.run_tests }}

.github/workflows/deploy-alpha.yml

Lines changed: 0 additions & 188 deletions
This file was deleted.

.github/workflows/deploy-beta.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,12 @@ jobs:
9292
cat > backend/.env << ENVEOF
9393
NODE_ENV=beta
9494
VERSION=${{ inputs.app_version }}
95-
BASE_URL=https://beta.proxy-smart.your-domain.com
95+
BASE_URL=${BASE_URL:?Set BASE_URL}
9696
PORT=3002
97-
FHIR_SERVER_BASE=https://hapi.fhir.org/baseR4
98-
KEYCLOAK_BASE_URL=https://auth-beta.proxy-smart.your-domain.com
97+
FHIR_SERVER_BASE=${FHIR_SERVER_BASE:-https://hapi.fhir.org/baseR4}
98+
KEYCLOAK_BASE_URL=${KEYCLOAK_BASE_URL:?Set KEYCLOAK_BASE_URL}
9999
KEYCLOAK_REALM=proxy-smart
100-
DATABASE_URL=postgresql://proxyuser:secure_password@localhost:5432/proxy_smart_beta
100+
DATABASE_URL=${DATABASE_URL:?Set DATABASE_URL}
101101
ENVEOF
102102
103103
# Restart services

.github/workflows/deployment-strategy.yml

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,6 @@ on:
3232
description: "Target platform where app was deployed"
3333
value: ${{ jobs.output-deployment-urls.outputs.deployment_target }}
3434
secrets:
35-
FLY_API_TOKEN:
36-
required: false
37-
ALPHA_DB_PASSWORD:
38-
required: false
3935
VPS_SSH_KEY:
4036
required: false
4137
VPS_HOST:
@@ -56,19 +52,6 @@ on:
5652
required: false
5753

5854
jobs:
59-
# DEPRECATED: Alpha deployment is now handled automatically by Northflank CD
60-
# This job is kept as reference but should not be called
61-
deploy-alpha:
62-
name: Deploy Alpha (DEPRECATED - Northflank handles this automatically)
63-
if: inputs.deployment_stage == 'alpha' && false # Disabled - Northflank CD handles alpha deployment
64-
uses: ./.github/workflows/deploy-alpha.yml
65-
with:
66-
app_version: ${{ inputs.app_version }}
67-
source_branch: ${{ inputs.source_branch }}
68-
secrets:
69-
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
70-
ALPHA_DB_PASSWORD: ${{ secrets.ALPHA_DB_PASSWORD }}
71-
7255
deploy-beta:
7356
name: Deploy Beta (VPS)
7457
if: inputs.deployment_stage == 'beta'
@@ -98,7 +81,7 @@ jobs:
9881
output-deployment-urls:
9982
name: Output Deployment URLs
10083
runs-on: ubuntu-latest
101-
needs: [deploy-alpha, deploy-beta, deploy-production]
84+
needs: [deploy-beta, deploy-production]
10285
if: always()
10386
outputs:
10487
fhir_server_url: ${{ steps.set-outputs.outputs.fhir_server_url }}
@@ -118,22 +101,7 @@ jobs:
118101
echo "deployment_target=unknown" >> $GITHUB_OUTPUT
119102
120103
# Determine the job result and set appropriate values
121-
if [ "${{ inputs.deployment_stage }}" = "alpha" ]; then
122-
ALPHA_RESULT="${{ needs.deploy-alpha.result }}"
123-
echo "Alpha deployment result: $ALPHA_RESULT"
124-
125-
if [ "$ALPHA_RESULT" = "success" ]; then
126-
echo "fhir_server_url=${{ needs.deploy-alpha.outputs.fhir_server_url }}" >> $GITHUB_OUTPUT
127-
echo "keycloak_url=${{ needs.deploy-alpha.outputs.keycloak_url }}" >> $GITHUB_OUTPUT
128-
echo "app_url=${{ needs.deploy-alpha.outputs.app_url }}" >> $GITHUB_OUTPUT
129-
echo "deployment_status=${{ needs.deploy-alpha.outputs.deployment_status }}" >> $GITHUB_OUTPUT
130-
echo "deployment_target=${{ needs.deploy-alpha.outputs.deployment_target }}" >> $GITHUB_OUTPUT
131-
else
132-
echo "deployment_status=$ALPHA_RESULT" >> $GITHUB_OUTPUT
133-
echo "deployment_target=northflank" >> $GITHUB_OUTPUT
134-
fi
135-
136-
elif [ "${{ inputs.deployment_stage }}" = "beta" ]; then
104+
if [ "${{ inputs.deployment_stage }}" = "beta" ]; then
137105
BETA_RESULT="${{ needs.deploy-beta.result }}"
138106
echo "Beta deployment result: $BETA_RESULT"
139107

.github/workflows/release-orchestrator.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ on:
5151
required: false
5252
DISCORD_WEBHOOK_URL:
5353
required: false
54-
FLY_API_TOKEN:
55-
required: false
5654
VPS_SSH_KEY:
5755
required: false
5856
VPS_HOST:
@@ -150,7 +148,7 @@ jobs:
150148
uses: ./.github/workflows/build-and-test.yml
151149
with:
152150
run_tests: true
153-
fail_on_test_failure: false
151+
fail_on_test_failure: true
154152

155153
# Create GitHub release
156154
release:

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ Then open:
6161
| Service | URL |
6262
|---|---|
6363
| Admin UI | http://localhost:3000 |
64-
| Backend API | http://localhost:8080 |
65-
| Keycloak | http://localhost:8090 |
64+
| Backend API | http://localhost:8445 |
65+
| Keycloak | http://localhost:8080 |
6666

6767
See the [Getting Started Guide](docs/tutorials/getting-started.md) for initial configuration.
6868

backend/.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,7 @@ yarn-error.log*
4040
**/*.tgz
4141
**/*.log
4242
package-lock.json
43-
**/*.bun
43+
**/*.bun
44+
45+
# Runtime MCP server config (managed via UI)
46+
mcp.json

backend/eslint.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { fileURLToPath } from "url";
77
const __dirname = path.dirname(fileURLToPath(import.meta.url));
88

99
export default tseslint.config(
10-
{ ignores: ["dist/**", "node_modules/**", "**/lib/api-client/**", "public/**"] },
10+
{ ignores: ["dist/**", "node_modules/**", "**/lib/api-client/**", "**/lib/mcp-registry-client/**", "public/**"] },
1111
{
1212
files: ["**/*.{js,ts}"],
1313
extends: [js.configs.recommended, ...tseslint.configs.recommended],

0 commit comments

Comments
 (0)