@kya-os/mcp-i-cloudflare 1.8.2 → 1.8.3
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.
- package/dist/__tests__/e2e/test-config.d.ts +37 -0
- package/dist/__tests__/e2e/test-config.d.ts.map +1 -0
- package/dist/__tests__/e2e/test-config.js +62 -0
- package/dist/__tests__/e2e/test-config.js.map +1 -0
- package/dist/consent-fallback-html.d.ts +11 -0
- package/dist/consent-fallback-html.d.ts.map +1 -0
- package/dist/consent-fallback-html.js +303 -0
- package/dist/consent-fallback-html.js.map +1 -0
- package/dist/services/consent-templates/template-renderer.d.ts +23 -12
- package/dist/services/consent-templates/template-renderer.d.ts.map +1 -1
- package/dist/services/consent-templates/template-renderer.js +17 -12
- package/dist/services/consent-templates/template-renderer.js.map +1 -1
- package/dist/services/consent.service.d.ts.map +1 -1
- package/dist/services/consent.service.js +55 -5
- package/dist/services/consent.service.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* E2E Test Configuration
|
|
3
|
+
*
|
|
4
|
+
* This file contains configuration for end-to-end tests that use real AgentShield API.
|
|
5
|
+
* Set these environment variables before running E2E tests:
|
|
6
|
+
*
|
|
7
|
+
* ```bash
|
|
8
|
+
* export E2E_AGENTSHIELD_API_KEY="sk_test_..."
|
|
9
|
+
* export E2E_AGENTSHIELD_PROJECT_ID="test-project-id"
|
|
10
|
+
* export E2E_AGENTSHIELD_API_URL="https://kya.vouched.id" # Optional, defaults to production
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* Or create a `.env.e2e` file in the package root:
|
|
14
|
+
* ```
|
|
15
|
+
* E2E_AGENTSHIELD_API_KEY=sk_test_...
|
|
16
|
+
* E2E_AGENTSHIELD_PROJECT_ID=test-project-id
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export interface E2ETestConfig {
|
|
20
|
+
apiKey: string;
|
|
21
|
+
projectId: string;
|
|
22
|
+
apiUrl: string;
|
|
23
|
+
enabled: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Load E2E test configuration from environment variables
|
|
27
|
+
*/
|
|
28
|
+
export declare function loadE2EConfig(): E2ETestConfig | null;
|
|
29
|
+
/**
|
|
30
|
+
* Check if E2E tests should run
|
|
31
|
+
*/
|
|
32
|
+
export declare function shouldRunE2ETests(): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Get E2E test configuration or throw if not configured
|
|
35
|
+
*/
|
|
36
|
+
export declare function getE2EConfig(): E2ETestConfig;
|
|
37
|
+
//# sourceMappingURL=test-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-config.d.ts","sourceRoot":"","sources":["../../../src/__tests__/e2e/test-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAWH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,aAAa,GAAG,IAAI,CAyBpD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAG3C;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,aAAa,CAU5C"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* E2E Test Configuration
|
|
3
|
+
*
|
|
4
|
+
* This file contains configuration for end-to-end tests that use real AgentShield API.
|
|
5
|
+
* Set these environment variables before running E2E tests:
|
|
6
|
+
*
|
|
7
|
+
* ```bash
|
|
8
|
+
* export E2E_AGENTSHIELD_API_KEY="sk_test_..."
|
|
9
|
+
* export E2E_AGENTSHIELD_PROJECT_ID="test-project-id"
|
|
10
|
+
* export E2E_AGENTSHIELD_API_URL="https://kya.vouched.id" # Optional, defaults to production
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* Or create a `.env.e2e` file in the package root:
|
|
14
|
+
* ```
|
|
15
|
+
* E2E_AGENTSHIELD_API_KEY=sk_test_...
|
|
16
|
+
* E2E_AGENTSHIELD_PROJECT_ID=test-project-id
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Load E2E test configuration from environment variables
|
|
21
|
+
*/
|
|
22
|
+
export function loadE2EConfig() {
|
|
23
|
+
// Access environment variables - works in Node.js (vitest) environment
|
|
24
|
+
const apiKey = typeof process !== "undefined" && process.env
|
|
25
|
+
? process.env.E2E_AGENTSHIELD_API_KEY
|
|
26
|
+
: undefined;
|
|
27
|
+
const projectId = typeof process !== "undefined" && process.env
|
|
28
|
+
? process.env.E2E_AGENTSHIELD_PROJECT_ID
|
|
29
|
+
: undefined;
|
|
30
|
+
const apiUrl = typeof process !== "undefined" && process.env
|
|
31
|
+
? process.env.E2E_AGENTSHIELD_API_URL || "https://kya.vouched.id"
|
|
32
|
+
: "https://kya.vouched.id";
|
|
33
|
+
if (!apiKey || !projectId) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
apiKey,
|
|
38
|
+
projectId,
|
|
39
|
+
apiUrl,
|
|
40
|
+
enabled: true,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Check if E2E tests should run
|
|
45
|
+
*/
|
|
46
|
+
export function shouldRunE2ETests() {
|
|
47
|
+
const config = loadE2EConfig();
|
|
48
|
+
return config !== null && config.enabled;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Get E2E test configuration or throw if not configured
|
|
52
|
+
*/
|
|
53
|
+
export function getE2EConfig() {
|
|
54
|
+
const config = loadE2EConfig();
|
|
55
|
+
if (!config) {
|
|
56
|
+
throw new Error("E2E tests require E2E_AGENTSHIELD_API_KEY and E2E_AGENTSHIELD_PROJECT_ID environment variables.\n" +
|
|
57
|
+
"Set them in your environment or create a .env.e2e file.\n" +
|
|
58
|
+
"See packages/mcp-i-cloudflare/src/__tests__/e2e/test-config.ts for details.");
|
|
59
|
+
}
|
|
60
|
+
return config;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=test-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-config.js","sourceRoot":"","sources":["../../../src/__tests__/e2e/test-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAkBH;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,uEAAuE;IACvE,MAAM,MAAM,GACV,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO,CAAC,GAAG;QAC3C,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB;QACrC,CAAC,CAAC,SAAS,CAAC;IAChB,MAAM,SAAS,GACb,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO,CAAC,GAAG;QAC3C,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,0BAA0B;QACxC,CAAC,CAAC,SAAS,CAAC;IAChB,MAAM,MAAM,GACV,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO,CAAC,GAAG;QAC3C,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,IAAI,wBAAwB;QACjE,CAAC,CAAC,wBAAwB,CAAC;IAE/B,IAAI,CAAC,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO;QACL,MAAM;QACN,SAAS;QACT,MAAM;QACN,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB;IAC/B,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;IAC/B,OAAO,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,OAAO,CAAC;AAC3C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;IAC/B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,mGAAmG;YACjG,2DAA2D;YAC3D,6EAA6E,CAChF,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal inline consent UI fallback.
|
|
3
|
+
*
|
|
4
|
+
* Used when @kya-os/consent is not available (optional peer dependency).
|
|
5
|
+
* This is the vanilla HTML/JS/CSS consent form with inline MCP Apps
|
|
6
|
+
* handshake that proves the data pipeline works end-to-end.
|
|
7
|
+
*
|
|
8
|
+
* The full Lit-based UI in @kya-os/consent/mcp-app is preferred when available.
|
|
9
|
+
*/
|
|
10
|
+
export declare const CONSENT_FALLBACK_HTML = "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <meta name=\"color-scheme\" content=\"light dark\">\n <title>MCPI Consent</title>\n <style>\n * { box-sizing: border-box; margin: 0; padding: 0; }\n body { font-family: system-ui, -apple-system, sans-serif; padding: 16px; background: transparent; }\n .card { border-radius: 12px; padding: 20px; border: 1px solid rgba(128,128,128,0.2); }\n h2 { font-size: 16px; font-weight: 600; margin-bottom: 8px; }\n p { font-size: 13px; opacity: 0.7; line-height: 1.5; margin-bottom: 6px; }\n .scopes { margin: 10px 0; }\n .scope { display: inline-block; padding: 3px 10px; border-radius: 10px; font-size: 12px; font-weight: 500; margin: 2px 4px 2px 0; background: rgba(46,125,50,0.1); color: #2e7d32; }\n .btn { display: inline-block; padding: 8px 20px; border-radius: 8px; border: none; font-size: 14px; font-weight: 500; cursor: pointer; margin-right: 8px; margin-top: 10px; }\n .btn-approve { background: #2563eb; color: #fff; }\n .btn-approve:disabled { opacity: 0.5; cursor: not-allowed; }\n .btn-deny { background: transparent; border: 1px solid rgba(128,128,128,0.3); }\n .info { font-size: 11px; opacity: 0.5; margin-top: 12px; }\n .fallback { font-size: 12px; margin-top: 8px; }\n .fallback a { color: #2563eb; }\n #loading { font-size: 13px; opacity: 0.6; }\n #consent { display: none; }\n #approved { display: none; font-size: 14px; color: #16a34a; font-weight: 500; }\n .cred-fields { display: none; margin: 12px 0; }\n .cred-fields label { display: block; font-size: 12px; font-weight: 500; margin-bottom: 4px; opacity: 0.8; }\n .cred-fields input[type=\"text\"],\n .cred-fields input[type=\"password\"] { width: 100%; padding: 8px 10px; border-radius: 6px; border: 1px solid rgba(128,128,128,0.3); font-size: 14px; margin-bottom: 10px; background: transparent; color: inherit; }\n .cred-fields input:focus { outline: none; border-color: #2563eb; }\n .pw-wrap { position: relative; }\n .pw-toggle { position: absolute; right: 8px; top: 8px; background: none; border: none; cursor: pointer; font-size: 13px; opacity: 0.5; color: inherit; }\n .terms-row { display: flex; align-items: flex-start; gap: 8px; margin: 10px 0 4px; }\n .terms-row input[type=\"checkbox\"] { margin-top: 2px; }\n .terms-row label { font-size: 12px; opacity: 0.7; cursor: pointer; }\n .auth-error { display: none; font-size: 13px; color: #dc2626; margin: 8px 0; padding: 8px 10px; border-radius: 6px; background: rgba(220,38,38,0.08); }\n </style>\n</head>\n<body>\n <div id=\"loading\">Waiting for consent data…</div>\n <div id=\"consent\" class=\"card\">\n <h2>Authorization Required</h2>\n <p id=\"tool-desc\"></p>\n <div id=\"scopes-container\" class=\"scopes\"></div>\n <div id=\"cred-fields\" class=\"cred-fields\">\n <label for=\"cred-username\">Username / Email</label>\n <input type=\"text\" id=\"cred-username\" autocomplete=\"username\" placeholder=\"Enter your username or email\">\n <label for=\"cred-password\">Password</label>\n <div class=\"pw-wrap\">\n <input type=\"password\" id=\"cred-password\" autocomplete=\"current-password\" placeholder=\"Enter your password\">\n <button type=\"button\" class=\"pw-toggle\" id=\"pw-toggle\" aria-label=\"Toggle password visibility\">Show</button>\n </div>\n </div>\n <div id=\"auth-error\" class=\"auth-error\"></div>\n <div id=\"terms-row\" class=\"terms-row\" style=\"display:none;\">\n <input type=\"checkbox\" id=\"terms-check\">\n <label for=\"terms-check\">I agree to authorize this tool and accept the terms of service</label>\n </div>\n <p id=\"agent-info\" class=\"info\"></p>\n <div>\n <button class=\"btn btn-approve\" id=\"approve-btn\">Approve</button>\n <button class=\"btn btn-deny\" id=\"deny-btn\">Deny</button>\n </div>\n <div class=\"fallback\" id=\"fallback\"></div>\n </div>\n <div id=\"approved\"></div>\n <script>\n (function() {\n var send = function(msg) { window.parent.postMessage(msg, \"*\"); };\n var consentData = null;\n var authMode = \"consent-only\";\n\n function resizeNotify() {\n send({ jsonrpc: \"2.0\", method: \"ui/notifications/size-changed\", params: {\n width: document.documentElement.scrollWidth,\n height: document.documentElement.scrollHeight\n }});\n }\n\n function showConsent(data) {\n consentData = data;\n authMode = data.authMode || \"consent-only\";\n document.getElementById(\"loading\").style.display = \"none\";\n document.getElementById(\"consent\").style.display = \"block\";\n\n if (authMode === \"credentials\") {\n document.getElementById(\"tool-desc\").textContent =\n \"Tool \\u201c\" + (data.tool || \"unknown\") + \"\\u201d requires authentication.\";\n document.getElementById(\"cred-fields\").style.display = \"block\";\n document.getElementById(\"terms-row\").style.display = \"flex\";\n document.getElementById(\"approve-btn\").textContent = \"Sign In & Authorize\";\n document.getElementById(\"approve-btn\").disabled = true;\n document.getElementById(\"terms-check\").addEventListener(\"change\", function() {\n document.getElementById(\"approve-btn\").disabled = !this.checked;\n });\n } else {\n document.getElementById(\"tool-desc\").textContent =\n \"Tool \\u201c\" + (data.tool || \"unknown\") + \"\\u201d requires your approval.\";\n }\n\n var scopesEl = document.getElementById(\"scopes-container\");\n var scopes = data.scopes || [];\n scopesEl.textContent = \"\";\n scopes.forEach(function(s) {\n var span = document.createElement(\"span\");\n span.className = \"scope\";\n span.textContent = s;\n scopesEl.appendChild(span);\n });\n document.getElementById(\"agent-info\").textContent =\n \"Agent: \" + (data.agentName || data.agentDid || \"unknown\");\n if (data.consentUrl) {\n var fallbackEl = document.getElementById(\"fallback\");\n fallbackEl.textContent = \"\";\n var a = document.createElement(\"a\");\n a.href = data.consentUrl;\n a.target = \"_blank\";\n a.rel = \"noopener\";\n a.textContent = \"Open in browser\";\n fallbackEl.appendChild(a);\n }\n resizeNotify();\n }\n\n document.getElementById(\"pw-toggle\").addEventListener(\"click\", function() {\n var pwInput = document.getElementById(\"cred-password\");\n if (pwInput.type === \"password\") {\n pwInput.type = \"text\";\n this.textContent = \"Hide\";\n } else {\n pwInput.type = \"password\";\n this.textContent = \"Show\";\n }\n });\n\n var pendingRequests = {};\n var nextId = 100;\n\n function handleApprovalResponse(result, error) {\n var statusEl = document.getElementById(\"approved\");\n if (error) {\n if (authMode === \"credentials\") {\n var errEl = document.getElementById(\"auth-error\");\n errEl.textContent = error.message || JSON.stringify(error);\n errEl.style.display = \"block\";\n document.getElementById(\"consent\").style.display = \"block\";\n statusEl.style.display = \"none\";\n document.getElementById(\"approve-btn\").disabled = !document.getElementById(\"terms-check\").checked;\n resizeNotify();\n return;\n }\n statusEl.textContent = \"Approval error: \" + (error.message || JSON.stringify(error));\n statusEl.style.color = \"#dc2626\";\n } else {\n try {\n var text = result && result.content && result.content[0] && result.content[0].text;\n var respData = text ? JSON.parse(text) : {};\n if (respData.success) {\n statusEl.textContent = \"Authorization granted. You can now retry the tool.\";\n statusEl.style.color = \"#22c55e\";\n } else {\n if (authMode === \"credentials\" && (respData.error_code === \"auth_failed\" || respData.error_code === \"validation_error\")) {\n var errEl = document.getElementById(\"auth-error\");\n errEl.textContent = respData.error || \"Authentication failed. Please check your credentials.\";\n errEl.style.display = \"block\";\n document.getElementById(\"consent\").style.display = \"block\";\n statusEl.style.display = \"none\";\n document.getElementById(\"approve-btn\").disabled = !document.getElementById(\"terms-check\").checked;\n resizeNotify();\n return;\n }\n statusEl.textContent = \"Approval error: \" + (respData.error || respData.error_code || \"Unknown\");\n statusEl.style.color = \"#f59e0b\";\n }\n } catch(e) {\n statusEl.textContent = \"Unexpected response\";\n statusEl.style.color = \"#f59e0b\";\n }\n }\n resizeNotify();\n }\n\n document.getElementById(\"approve-btn\").addEventListener(\"click\", function() {\n if (!consentData) return;\n document.getElementById(\"auth-error\").style.display = \"none\";\n var statusEl = document.getElementById(\"approved\");\n document.getElementById(\"consent\").style.display = \"none\";\n statusEl.style.display = \"block\";\n statusEl.textContent = authMode === \"credentials\" ? \"Authenticating...\" : \"Sending approval...\";\n statusEl.style.color = \"\";\n var reqId = nextId++;\n pendingRequests[reqId] = handleApprovalResponse;\n\n if (authMode === \"credentials\") {\n var username = document.getElementById(\"cred-username\").value;\n var password = document.getElementById(\"cred-password\").value;\n if (!username || !password) {\n statusEl.style.display = \"none\";\n document.getElementById(\"consent\").style.display = \"block\";\n var errEl = document.getElementById(\"auth-error\");\n errEl.textContent = \"Please enter both username and password.\";\n errEl.style.display = \"block\";\n resizeNotify();\n return;\n }\n send({\n jsonrpc: \"2.0\", id: reqId, method: \"tools/call\",\n params: {\n name: \"_mcpi_credential_auth\",\n arguments: {\n tool: consentData.tool,\n scopes: consentData.scopes,\n session_id: consentData.sessionId,\n agent_did: consentData.agentDid,\n project_id: consentData.projectId,\n resume_token: consentData.resumeToken,\n username: username,\n password: password,\n provider: consentData.provider || \"credentials\"\n }\n }\n });\n } else {\n send({\n jsonrpc: \"2.0\", id: reqId, method: \"tools/call\",\n params: {\n name: \"_mcpi_approve_consent\",\n arguments: {\n tool: consentData.tool,\n scopes: consentData.scopes,\n session_id: consentData.sessionId,\n agent_did: consentData.agentDid,\n project_id: consentData.projectId,\n resume_token: consentData.resumeToken\n }\n }\n });\n }\n resizeNotify();\n });\n\n document.getElementById(\"deny-btn\").addEventListener(\"click\", function() {\n document.getElementById(\"consent\").style.display = \"none\";\n document.getElementById(\"approved\").style.display = \"block\";\n document.getElementById(\"approved\").textContent = \"Authorization denied.\";\n document.getElementById(\"approved\").style.color = \"#dc2626\";\n resizeNotify();\n });\n\n window.addEventListener(\"message\", function(e) {\n if (e.source !== window.parent) return;\n var msg = e.data;\n if (!msg || msg.jsonrpc !== \"2.0\") return;\n\n if (msg.id === 0 && msg.result) {\n var ctx = msg.result.hostContext || {};\n if (ctx.theme === \"dark\") document.documentElement.style.colorScheme = \"dark\";\n send({ jsonrpc: \"2.0\", method: \"ui/notifications/initialized\" });\n resizeNotify();\n }\n if (msg.id != null && pendingRequests[msg.id]) {\n pendingRequests[msg.id](msg.result, msg.error);\n delete pendingRequests[msg.id];\n }\n if (msg.method === \"ui/notifications/tool-result\" && msg.params) {\n var sc = msg.params.structuredContent;\n if (sc && sc.type === \"consent_required\") showConsent(sc);\n }\n if (msg.method === \"ui/notifications/tool-input\" && msg.params) {\n var args = msg.params.arguments;\n if (args && args.type === \"consent_required\") showConsent(args);\n }\n if (msg.method === \"ping\" && msg.id != null) {\n send({ jsonrpc: \"2.0\", id: msg.id, result: {} });\n }\n if (msg.method === \"ui/resource-teardown\" && msg.id != null) {\n send({ jsonrpc: \"2.0\", id: msg.id, result: {} });\n }\n });\n\n send({\n jsonrpc: \"2.0\", id: 0, method: \"ui/initialize\",\n params: {\n appInfo: { name: \"MCPI Consent\", version: \"1.0.0\" },\n appCapabilities: {},\n protocolVersion: \"2026-01-26\"\n }\n });\n })();\n </script>\n</body>\n</html>";
|
|
11
|
+
//# sourceMappingURL=consent-fallback-html.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consent-fallback-html.d.ts","sourceRoot":"","sources":["../src/consent-fallback-html.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,eAAO,MAAM,qBAAqB,usbAmS1B,CAAC"}
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal inline consent UI fallback.
|
|
3
|
+
*
|
|
4
|
+
* Used when @kya-os/consent is not available (optional peer dependency).
|
|
5
|
+
* This is the vanilla HTML/JS/CSS consent form with inline MCP Apps
|
|
6
|
+
* handshake that proves the data pipeline works end-to-end.
|
|
7
|
+
*
|
|
8
|
+
* The full Lit-based UI in @kya-os/consent/mcp-app is preferred when available.
|
|
9
|
+
*/
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
11
|
+
export const CONSENT_FALLBACK_HTML = `<!DOCTYPE html>
|
|
12
|
+
<html lang="en">
|
|
13
|
+
<head>
|
|
14
|
+
<meta charset="utf-8">
|
|
15
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
16
|
+
<meta name="color-scheme" content="light dark">
|
|
17
|
+
<title>MCPI Consent</title>
|
|
18
|
+
<style>
|
|
19
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
20
|
+
body { font-family: system-ui, -apple-system, sans-serif; padding: 16px; background: transparent; }
|
|
21
|
+
.card { border-radius: 12px; padding: 20px; border: 1px solid rgba(128,128,128,0.2); }
|
|
22
|
+
h2 { font-size: 16px; font-weight: 600; margin-bottom: 8px; }
|
|
23
|
+
p { font-size: 13px; opacity: 0.7; line-height: 1.5; margin-bottom: 6px; }
|
|
24
|
+
.scopes { margin: 10px 0; }
|
|
25
|
+
.scope { display: inline-block; padding: 3px 10px; border-radius: 10px; font-size: 12px; font-weight: 500; margin: 2px 4px 2px 0; background: rgba(46,125,50,0.1); color: #2e7d32; }
|
|
26
|
+
.btn { display: inline-block; padding: 8px 20px; border-radius: 8px; border: none; font-size: 14px; font-weight: 500; cursor: pointer; margin-right: 8px; margin-top: 10px; }
|
|
27
|
+
.btn-approve { background: #2563eb; color: #fff; }
|
|
28
|
+
.btn-approve:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
29
|
+
.btn-deny { background: transparent; border: 1px solid rgba(128,128,128,0.3); }
|
|
30
|
+
.info { font-size: 11px; opacity: 0.5; margin-top: 12px; }
|
|
31
|
+
.fallback { font-size: 12px; margin-top: 8px; }
|
|
32
|
+
.fallback a { color: #2563eb; }
|
|
33
|
+
#loading { font-size: 13px; opacity: 0.6; }
|
|
34
|
+
#consent { display: none; }
|
|
35
|
+
#approved { display: none; font-size: 14px; color: #16a34a; font-weight: 500; }
|
|
36
|
+
.cred-fields { display: none; margin: 12px 0; }
|
|
37
|
+
.cred-fields label { display: block; font-size: 12px; font-weight: 500; margin-bottom: 4px; opacity: 0.8; }
|
|
38
|
+
.cred-fields input[type="text"],
|
|
39
|
+
.cred-fields input[type="password"] { width: 100%; padding: 8px 10px; border-radius: 6px; border: 1px solid rgba(128,128,128,0.3); font-size: 14px; margin-bottom: 10px; background: transparent; color: inherit; }
|
|
40
|
+
.cred-fields input:focus { outline: none; border-color: #2563eb; }
|
|
41
|
+
.pw-wrap { position: relative; }
|
|
42
|
+
.pw-toggle { position: absolute; right: 8px; top: 8px; background: none; border: none; cursor: pointer; font-size: 13px; opacity: 0.5; color: inherit; }
|
|
43
|
+
.terms-row { display: flex; align-items: flex-start; gap: 8px; margin: 10px 0 4px; }
|
|
44
|
+
.terms-row input[type="checkbox"] { margin-top: 2px; }
|
|
45
|
+
.terms-row label { font-size: 12px; opacity: 0.7; cursor: pointer; }
|
|
46
|
+
.auth-error { display: none; font-size: 13px; color: #dc2626; margin: 8px 0; padding: 8px 10px; border-radius: 6px; background: rgba(220,38,38,0.08); }
|
|
47
|
+
</style>
|
|
48
|
+
</head>
|
|
49
|
+
<body>
|
|
50
|
+
<div id="loading">Waiting for consent data…</div>
|
|
51
|
+
<div id="consent" class="card">
|
|
52
|
+
<h2>Authorization Required</h2>
|
|
53
|
+
<p id="tool-desc"></p>
|
|
54
|
+
<div id="scopes-container" class="scopes"></div>
|
|
55
|
+
<div id="cred-fields" class="cred-fields">
|
|
56
|
+
<label for="cred-username">Username / Email</label>
|
|
57
|
+
<input type="text" id="cred-username" autocomplete="username" placeholder="Enter your username or email">
|
|
58
|
+
<label for="cred-password">Password</label>
|
|
59
|
+
<div class="pw-wrap">
|
|
60
|
+
<input type="password" id="cred-password" autocomplete="current-password" placeholder="Enter your password">
|
|
61
|
+
<button type="button" class="pw-toggle" id="pw-toggle" aria-label="Toggle password visibility">Show</button>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
<div id="auth-error" class="auth-error"></div>
|
|
65
|
+
<div id="terms-row" class="terms-row" style="display:none;">
|
|
66
|
+
<input type="checkbox" id="terms-check">
|
|
67
|
+
<label for="terms-check">I agree to authorize this tool and accept the terms of service</label>
|
|
68
|
+
</div>
|
|
69
|
+
<p id="agent-info" class="info"></p>
|
|
70
|
+
<div>
|
|
71
|
+
<button class="btn btn-approve" id="approve-btn">Approve</button>
|
|
72
|
+
<button class="btn btn-deny" id="deny-btn">Deny</button>
|
|
73
|
+
</div>
|
|
74
|
+
<div class="fallback" id="fallback"></div>
|
|
75
|
+
</div>
|
|
76
|
+
<div id="approved"></div>
|
|
77
|
+
<script>
|
|
78
|
+
(function() {
|
|
79
|
+
var send = function(msg) { window.parent.postMessage(msg, "*"); };
|
|
80
|
+
var consentData = null;
|
|
81
|
+
var authMode = "consent-only";
|
|
82
|
+
|
|
83
|
+
function resizeNotify() {
|
|
84
|
+
send({ jsonrpc: "2.0", method: "ui/notifications/size-changed", params: {
|
|
85
|
+
width: document.documentElement.scrollWidth,
|
|
86
|
+
height: document.documentElement.scrollHeight
|
|
87
|
+
}});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function showConsent(data) {
|
|
91
|
+
consentData = data;
|
|
92
|
+
authMode = data.authMode || "consent-only";
|
|
93
|
+
document.getElementById("loading").style.display = "none";
|
|
94
|
+
document.getElementById("consent").style.display = "block";
|
|
95
|
+
|
|
96
|
+
if (authMode === "credentials") {
|
|
97
|
+
document.getElementById("tool-desc").textContent =
|
|
98
|
+
"Tool \\u201c" + (data.tool || "unknown") + "\\u201d requires authentication.";
|
|
99
|
+
document.getElementById("cred-fields").style.display = "block";
|
|
100
|
+
document.getElementById("terms-row").style.display = "flex";
|
|
101
|
+
document.getElementById("approve-btn").textContent = "Sign In & Authorize";
|
|
102
|
+
document.getElementById("approve-btn").disabled = true;
|
|
103
|
+
document.getElementById("terms-check").addEventListener("change", function() {
|
|
104
|
+
document.getElementById("approve-btn").disabled = !this.checked;
|
|
105
|
+
});
|
|
106
|
+
} else {
|
|
107
|
+
document.getElementById("tool-desc").textContent =
|
|
108
|
+
"Tool \\u201c" + (data.tool || "unknown") + "\\u201d requires your approval.";
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
var scopesEl = document.getElementById("scopes-container");
|
|
112
|
+
var scopes = data.scopes || [];
|
|
113
|
+
scopesEl.textContent = "";
|
|
114
|
+
scopes.forEach(function(s) {
|
|
115
|
+
var span = document.createElement("span");
|
|
116
|
+
span.className = "scope";
|
|
117
|
+
span.textContent = s;
|
|
118
|
+
scopesEl.appendChild(span);
|
|
119
|
+
});
|
|
120
|
+
document.getElementById("agent-info").textContent =
|
|
121
|
+
"Agent: " + (data.agentName || data.agentDid || "unknown");
|
|
122
|
+
if (data.consentUrl) {
|
|
123
|
+
var fallbackEl = document.getElementById("fallback");
|
|
124
|
+
fallbackEl.textContent = "";
|
|
125
|
+
var a = document.createElement("a");
|
|
126
|
+
a.href = data.consentUrl;
|
|
127
|
+
a.target = "_blank";
|
|
128
|
+
a.rel = "noopener";
|
|
129
|
+
a.textContent = "Open in browser";
|
|
130
|
+
fallbackEl.appendChild(a);
|
|
131
|
+
}
|
|
132
|
+
resizeNotify();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
document.getElementById("pw-toggle").addEventListener("click", function() {
|
|
136
|
+
var pwInput = document.getElementById("cred-password");
|
|
137
|
+
if (pwInput.type === "password") {
|
|
138
|
+
pwInput.type = "text";
|
|
139
|
+
this.textContent = "Hide";
|
|
140
|
+
} else {
|
|
141
|
+
pwInput.type = "password";
|
|
142
|
+
this.textContent = "Show";
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
var pendingRequests = {};
|
|
147
|
+
var nextId = 100;
|
|
148
|
+
|
|
149
|
+
function handleApprovalResponse(result, error) {
|
|
150
|
+
var statusEl = document.getElementById("approved");
|
|
151
|
+
if (error) {
|
|
152
|
+
if (authMode === "credentials") {
|
|
153
|
+
var errEl = document.getElementById("auth-error");
|
|
154
|
+
errEl.textContent = error.message || JSON.stringify(error);
|
|
155
|
+
errEl.style.display = "block";
|
|
156
|
+
document.getElementById("consent").style.display = "block";
|
|
157
|
+
statusEl.style.display = "none";
|
|
158
|
+
document.getElementById("approve-btn").disabled = !document.getElementById("terms-check").checked;
|
|
159
|
+
resizeNotify();
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
statusEl.textContent = "Approval error: " + (error.message || JSON.stringify(error));
|
|
163
|
+
statusEl.style.color = "#dc2626";
|
|
164
|
+
} else {
|
|
165
|
+
try {
|
|
166
|
+
var text = result && result.content && result.content[0] && result.content[0].text;
|
|
167
|
+
var respData = text ? JSON.parse(text) : {};
|
|
168
|
+
if (respData.success) {
|
|
169
|
+
statusEl.textContent = "Authorization granted. You can now retry the tool.";
|
|
170
|
+
statusEl.style.color = "#22c55e";
|
|
171
|
+
} else {
|
|
172
|
+
if (authMode === "credentials" && (respData.error_code === "auth_failed" || respData.error_code === "validation_error")) {
|
|
173
|
+
var errEl = document.getElementById("auth-error");
|
|
174
|
+
errEl.textContent = respData.error || "Authentication failed. Please check your credentials.";
|
|
175
|
+
errEl.style.display = "block";
|
|
176
|
+
document.getElementById("consent").style.display = "block";
|
|
177
|
+
statusEl.style.display = "none";
|
|
178
|
+
document.getElementById("approve-btn").disabled = !document.getElementById("terms-check").checked;
|
|
179
|
+
resizeNotify();
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
statusEl.textContent = "Approval error: " + (respData.error || respData.error_code || "Unknown");
|
|
183
|
+
statusEl.style.color = "#f59e0b";
|
|
184
|
+
}
|
|
185
|
+
} catch(e) {
|
|
186
|
+
statusEl.textContent = "Unexpected response";
|
|
187
|
+
statusEl.style.color = "#f59e0b";
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
resizeNotify();
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
document.getElementById("approve-btn").addEventListener("click", function() {
|
|
194
|
+
if (!consentData) return;
|
|
195
|
+
document.getElementById("auth-error").style.display = "none";
|
|
196
|
+
var statusEl = document.getElementById("approved");
|
|
197
|
+
document.getElementById("consent").style.display = "none";
|
|
198
|
+
statusEl.style.display = "block";
|
|
199
|
+
statusEl.textContent = authMode === "credentials" ? "Authenticating..." : "Sending approval...";
|
|
200
|
+
statusEl.style.color = "";
|
|
201
|
+
var reqId = nextId++;
|
|
202
|
+
pendingRequests[reqId] = handleApprovalResponse;
|
|
203
|
+
|
|
204
|
+
if (authMode === "credentials") {
|
|
205
|
+
var username = document.getElementById("cred-username").value;
|
|
206
|
+
var password = document.getElementById("cred-password").value;
|
|
207
|
+
if (!username || !password) {
|
|
208
|
+
statusEl.style.display = "none";
|
|
209
|
+
document.getElementById("consent").style.display = "block";
|
|
210
|
+
var errEl = document.getElementById("auth-error");
|
|
211
|
+
errEl.textContent = "Please enter both username and password.";
|
|
212
|
+
errEl.style.display = "block";
|
|
213
|
+
resizeNotify();
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
send({
|
|
217
|
+
jsonrpc: "2.0", id: reqId, method: "tools/call",
|
|
218
|
+
params: {
|
|
219
|
+
name: "_mcpi_credential_auth",
|
|
220
|
+
arguments: {
|
|
221
|
+
tool: consentData.tool,
|
|
222
|
+
scopes: consentData.scopes,
|
|
223
|
+
session_id: consentData.sessionId,
|
|
224
|
+
agent_did: consentData.agentDid,
|
|
225
|
+
project_id: consentData.projectId,
|
|
226
|
+
resume_token: consentData.resumeToken,
|
|
227
|
+
username: username,
|
|
228
|
+
password: password,
|
|
229
|
+
provider: consentData.provider || "credentials"
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
} else {
|
|
234
|
+
send({
|
|
235
|
+
jsonrpc: "2.0", id: reqId, method: "tools/call",
|
|
236
|
+
params: {
|
|
237
|
+
name: "_mcpi_approve_consent",
|
|
238
|
+
arguments: {
|
|
239
|
+
tool: consentData.tool,
|
|
240
|
+
scopes: consentData.scopes,
|
|
241
|
+
session_id: consentData.sessionId,
|
|
242
|
+
agent_did: consentData.agentDid,
|
|
243
|
+
project_id: consentData.projectId,
|
|
244
|
+
resume_token: consentData.resumeToken
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
resizeNotify();
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
document.getElementById("deny-btn").addEventListener("click", function() {
|
|
253
|
+
document.getElementById("consent").style.display = "none";
|
|
254
|
+
document.getElementById("approved").style.display = "block";
|
|
255
|
+
document.getElementById("approved").textContent = "Authorization denied.";
|
|
256
|
+
document.getElementById("approved").style.color = "#dc2626";
|
|
257
|
+
resizeNotify();
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
window.addEventListener("message", function(e) {
|
|
261
|
+
if (e.source !== window.parent) return;
|
|
262
|
+
var msg = e.data;
|
|
263
|
+
if (!msg || msg.jsonrpc !== "2.0") return;
|
|
264
|
+
|
|
265
|
+
if (msg.id === 0 && msg.result) {
|
|
266
|
+
var ctx = msg.result.hostContext || {};
|
|
267
|
+
if (ctx.theme === "dark") document.documentElement.style.colorScheme = "dark";
|
|
268
|
+
send({ jsonrpc: "2.0", method: "ui/notifications/initialized" });
|
|
269
|
+
resizeNotify();
|
|
270
|
+
}
|
|
271
|
+
if (msg.id != null && pendingRequests[msg.id]) {
|
|
272
|
+
pendingRequests[msg.id](msg.result, msg.error);
|
|
273
|
+
delete pendingRequests[msg.id];
|
|
274
|
+
}
|
|
275
|
+
if (msg.method === "ui/notifications/tool-result" && msg.params) {
|
|
276
|
+
var sc = msg.params.structuredContent;
|
|
277
|
+
if (sc && sc.type === "consent_required") showConsent(sc);
|
|
278
|
+
}
|
|
279
|
+
if (msg.method === "ui/notifications/tool-input" && msg.params) {
|
|
280
|
+
var args = msg.params.arguments;
|
|
281
|
+
if (args && args.type === "consent_required") showConsent(args);
|
|
282
|
+
}
|
|
283
|
+
if (msg.method === "ping" && msg.id != null) {
|
|
284
|
+
send({ jsonrpc: "2.0", id: msg.id, result: {} });
|
|
285
|
+
}
|
|
286
|
+
if (msg.method === "ui/resource-teardown" && msg.id != null) {
|
|
287
|
+
send({ jsonrpc: "2.0", id: msg.id, result: {} });
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
send({
|
|
292
|
+
jsonrpc: "2.0", id: 0, method: "ui/initialize",
|
|
293
|
+
params: {
|
|
294
|
+
appInfo: { name: "MCPI Consent", version: "1.0.0" },
|
|
295
|
+
appCapabilities: {},
|
|
296
|
+
protocolVersion: "2026-01-26"
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
})();
|
|
300
|
+
</script>
|
|
301
|
+
</body>
|
|
302
|
+
</html>`;
|
|
303
|
+
//# sourceMappingURL=consent-fallback-html.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consent-fallback-html.js","sourceRoot":"","sources":["../src/consent-fallback-html.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,gEAAgE;AAChE,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAmS7B,CAAC"}
|
|
@@ -11,6 +11,26 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import type { ConsentPageConfig, OAuthIdentity } from "@kya-os/contracts/consent";
|
|
13
13
|
import type { CredentialProviderConfig } from "@kya-os/contracts/config";
|
|
14
|
+
import { type ConsentUI, type CredentialsConfig } from "@kya-os/consent";
|
|
15
|
+
/**
|
|
16
|
+
* ConsentPageConfig extended with fields that flow through from AgentShield
|
|
17
|
+
* remote config but are intentionally excluded from the contracts type.
|
|
18
|
+
*/
|
|
19
|
+
type RendererPageConfig = ConsentPageConfig & {
|
|
20
|
+
oauthRequired?: boolean;
|
|
21
|
+
oauthUrl?: string;
|
|
22
|
+
credentialProviderType?: string;
|
|
23
|
+
credentialProvider?: string;
|
|
24
|
+
userDid?: string;
|
|
25
|
+
credentialUserEmail?: string;
|
|
26
|
+
credentialProviderUserId?: string;
|
|
27
|
+
oauthProviderType?: string;
|
|
28
|
+
oauthProviderName?: string;
|
|
29
|
+
ui?: ConsentUI;
|
|
30
|
+
credentials?: CredentialsConfig;
|
|
31
|
+
expirationDays?: number;
|
|
32
|
+
agentName?: string;
|
|
33
|
+
};
|
|
14
34
|
/**
|
|
15
35
|
* Template-based consent page renderer.
|
|
16
36
|
*
|
|
@@ -38,17 +58,7 @@ export declare class TemplateRenderer {
|
|
|
38
58
|
* @param oauthIdentity - Optional OAuth identity from cookie
|
|
39
59
|
* @returns HTML string
|
|
40
60
|
*/
|
|
41
|
-
render(config:
|
|
42
|
-
oauthRequired?: boolean;
|
|
43
|
-
oauthUrl?: string;
|
|
44
|
-
credentialProviderType?: string;
|
|
45
|
-
credentialProvider?: string;
|
|
46
|
-
userDid?: string;
|
|
47
|
-
credentialUserEmail?: string;
|
|
48
|
-
credentialProviderUserId?: string;
|
|
49
|
-
oauthProviderType?: string;
|
|
50
|
-
oauthProviderName?: string;
|
|
51
|
-
}, oauthIdentity?: OAuthIdentity): string;
|
|
61
|
+
render(config: RendererPageConfig, oauthIdentity?: OAuthIdentity): string;
|
|
52
62
|
/**
|
|
53
63
|
* Render consent page using Client-Side Rendering (CSR).
|
|
54
64
|
*
|
|
@@ -73,7 +83,7 @@ export declare class TemplateRenderer {
|
|
|
73
83
|
* @param authorizationType - Authorization type from tool protection config (default: 'password')
|
|
74
84
|
* @returns HTML string
|
|
75
85
|
*/
|
|
76
|
-
renderCredentialPage(config:
|
|
86
|
+
renderCredentialPage(config: RendererPageConfig, credentialConfig: CredentialProviderConfig, provider: string, csrfToken: string, authorizationType?: string): string;
|
|
77
87
|
/**
|
|
78
88
|
* Render credential login page using CSR (Client-Side Rendering).
|
|
79
89
|
*
|
|
@@ -125,4 +135,5 @@ export declare function createTemplateRenderer(options?: {
|
|
|
125
135
|
useCSR?: boolean;
|
|
126
136
|
bundlePath?: string;
|
|
127
137
|
}): TemplateRenderer;
|
|
138
|
+
export {};
|
|
128
139
|
//# sourceMappingURL=template-renderer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template-renderer.d.ts","sourceRoot":"","sources":["../../../src/services/consent-templates/template-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAYH,OAAO,KAAK,EACV,iBAAiB,EACjB,aAAa,EACd,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"template-renderer.d.ts","sourceRoot":"","sources":["../../../src/services/consent-templates/template-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAYH,OAAO,KAAK,EACV,iBAAiB,EACjB,aAAa,EACd,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACzE,OAAO,EAIL,KAAK,SAAS,EACd,KAAK,iBAAiB,EACvB,MAAM,iBAAiB,CAAC;AAQzB;;;GAGG;AACH,KAAK,kBAAkB,GAAG,iBAAiB,GAAG;IAC5C,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,EAAE,CAAC,EAAE,SAAS,CAAC;IACf,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;;;;;;GASG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,UAAU,CAAS;gBAEf,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE;IAK/D;;;;;;;;;OASG;IACH,MAAM,CACJ,MAAM,EAAE,kBAAkB,EAC1B,aAAa,CAAC,EAAE,aAAa,GAC5B,MAAM;IAoCT;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,SAAS;IAgEjB;;;;;;;;;OASG;IACH,oBAAoB,CAClB,MAAM,EAAE,kBAAkB,EAC1B,gBAAgB,EAAE,wBAAwB,EAC1C,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,iBAAiB,GAAE,MAAmB,GACrC,MAAM;IA+BT;;;;;;;;;OASG;IACH,OAAO,CAAC,uBAAuB;IAuD/B;;;;;;OAMG;IACH,aAAa,CAAC,OAAO,EAAE;QACrB,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,CAAC,EAAE,OAAO,CAAC;KACrB,GAAG,MAAM;IAIV;;;;;;;OAOG;IACH,iBAAiB,CACf,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,OAAO,GAClB,MAAM;IAsDT;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA2B3B;;OAEG;IACH,OAAO,CAAC,iBAAiB;CAqC1B;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,CAAC,EAAE;IAC/C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,gBAAgB,CAEnB"}
|
|
@@ -91,6 +91,8 @@ export class TemplateRenderer {
|
|
|
91
91
|
ui: config.ui,
|
|
92
92
|
// Map credentials config if available
|
|
93
93
|
credentials: config.credentials,
|
|
94
|
+
// Map expiration days from AgentShield config
|
|
95
|
+
expirationDays: config.expirationDays,
|
|
94
96
|
// Map other mode configs
|
|
95
97
|
// CRITICAL: Include providerId for proper OAuth button URL construction
|
|
96
98
|
oauth: config.oauthRequired
|
|
@@ -116,6 +118,7 @@ export class TemplateRenderer {
|
|
|
116
118
|
// Set authMode explicitly for OAuth flow
|
|
117
119
|
// This ensures the mcp-consent component renders the OAuth button
|
|
118
120
|
authMode: config.oauthRequired ? "oauth" : undefined,
|
|
121
|
+
agentName: config.agentName, // Human-readable agent name for display
|
|
119
122
|
provider: config.provider, // Pass the OAuth provider name (e.g., 'github')
|
|
120
123
|
// CRITICAL: Pass pre-built OAuth URL directly to avoid constructing wrong URL
|
|
121
124
|
// This is the actual OAuth authorization URL (e.g., https://github.com/login/oauth/authorize?...)
|
|
@@ -191,6 +194,9 @@ export class TemplateRenderer {
|
|
|
191
194
|
terms: config.terms,
|
|
192
195
|
customFields: config.customFields,
|
|
193
196
|
ui: config.ui,
|
|
197
|
+
// Pass expiration days so the credential page shows the correct value
|
|
198
|
+
// (parity with renderCSR — otherwise the Lit component falls back to default)
|
|
199
|
+
expirationDays: config.expirationDays,
|
|
194
200
|
// Include credentials config for the Lit component
|
|
195
201
|
credentials: {
|
|
196
202
|
usernameLabel: cpc.usernameLabel || "Username",
|
|
@@ -215,6 +221,7 @@ export class TemplateRenderer {
|
|
|
215
221
|
pageTitle: consentConfig.ui?.title || "Permission Request",
|
|
216
222
|
// Force credentials mode
|
|
217
223
|
authMode: "credentials",
|
|
224
|
+
agentName: config.agentName,
|
|
218
225
|
provider: provider,
|
|
219
226
|
// Include CSRF token for form security
|
|
220
227
|
csrfToken: csrfToken,
|
|
@@ -307,7 +314,7 @@ export class TemplateRenderer {
|
|
|
307
314
|
provider: config.provider,
|
|
308
315
|
oauthUrl: config.oauthUrl,
|
|
309
316
|
oauthRequired: config.oauthRequired,
|
|
310
|
-
expirationDays:
|
|
317
|
+
expirationDays: config.expirationDays ?? 30,
|
|
311
318
|
// Pass through credential auth params for 3-screen flow
|
|
312
319
|
credentialProviderType: config.credentialProviderType,
|
|
313
320
|
credentialProvider: config.credentialProvider,
|
|
@@ -323,8 +330,6 @@ export class TemplateRenderer {
|
|
|
323
330
|
* Build ConsentConfigWithMeta from page config's branding/terms/ui.
|
|
324
331
|
*/
|
|
325
332
|
buildRemoteConfig(config) {
|
|
326
|
-
// Cast to any to access optional fields that may come from AgentShield
|
|
327
|
-
const extendedConfig = config;
|
|
328
333
|
const branding = config.branding;
|
|
329
334
|
return {
|
|
330
335
|
branding: config.branding
|
|
@@ -344,20 +349,20 @@ export class TemplateRenderer {
|
|
|
344
349
|
: undefined,
|
|
345
350
|
customFields: config.customFields,
|
|
346
351
|
// Map UI config for title, description, button text, etc.
|
|
347
|
-
ui:
|
|
352
|
+
ui: config.ui
|
|
348
353
|
? {
|
|
349
|
-
title:
|
|
350
|
-
description:
|
|
351
|
-
expirationText:
|
|
352
|
-
cancelButtonText:
|
|
353
|
-
submitButtonText:
|
|
354
|
-
permissionsHeader:
|
|
354
|
+
title: config.ui.title,
|
|
355
|
+
description: config.ui.description,
|
|
356
|
+
expirationText: config.ui.expirationText,
|
|
357
|
+
cancelButtonText: config.ui.cancelButtonText,
|
|
358
|
+
submitButtonText: config.ui.submitButtonText,
|
|
359
|
+
permissionsHeader: config.ui.permissionsHeader,
|
|
355
360
|
}
|
|
356
361
|
: undefined,
|
|
357
362
|
// Map credentials config
|
|
358
|
-
credentials:
|
|
363
|
+
credentials: config.credentials,
|
|
359
364
|
// Map expiration days
|
|
360
|
-
expirationDays:
|
|
365
|
+
expirationDays: config.expirationDays,
|
|
361
366
|
};
|
|
362
367
|
}
|
|
363
368
|
}
|