tru-mcp 0.2.0 → 0.3.1
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/README.md +32 -8
- package/dist/api-client.d.ts +18 -0
- package/dist/api-client.js +52 -2
- package/dist/api-client.js.map +1 -1
- package/dist/init.js +51 -96
- package/dist/init.js.map +1 -1
- package/dist/server.js +6 -2
- package/dist/server.js.map +1 -1
- package/dist/tools/discover_api.d.ts +23 -0
- package/dist/tools/discover_api.js +73 -0
- package/dist/tools/discover_api.js.map +1 -0
- package/dist/tools/get_started.js +106 -7
- package/dist/tools/get_started.js.map +1 -1
- package/dist/tools/provision_user.d.ts +25 -0
- package/dist/tools/provision_user.js +84 -0
- package/dist/tools/provision_user.js.map +1 -0
- package/dist/tools/register_app.d.ts +2 -0
- package/dist/tools/register_app.js +64 -15
- package/dist/tools/register_app.js.map +1 -1
- package/dist/tools/request_user_data.d.ts +27 -0
- package/dist/tools/request_user_data.js +63 -0
- package/dist/tools/request_user_data.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,9 +8,17 @@ MCP server for [tru](https://tru-by29.onrender.com) — auth and billing API in
|
|
|
8
8
|
npx tru-mcp init
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
This detects your MCP client (Claude Code, Claude Desktop, Cursor) and writes the config automatically.
|
|
11
|
+
No API key needed. This detects your MCP client (Claude Code, Claude Desktop, Cursor) and writes the config automatically. Then tell your agent:
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
> "Run get_started to set up tru"
|
|
14
|
+
|
|
15
|
+
Your agent will register your app, get you an API key, connect Stripe, and discover your API — all in one conversation.
|
|
16
|
+
|
|
17
|
+
If you already have an API key:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx tru-mcp init --key tru_ak_your_key_here
|
|
21
|
+
```
|
|
14
22
|
|
|
15
23
|
### Manual Config
|
|
16
24
|
|
|
@@ -23,8 +31,7 @@ Add to your `.mcp.json` (Claude Code) or equivalent:
|
|
|
23
31
|
"command": "npx",
|
|
24
32
|
"args": ["-y", "tru-mcp"],
|
|
25
33
|
"env": {
|
|
26
|
-
"TRU_API_URL": "https://tru-by29.onrender.com"
|
|
27
|
-
"TRU_API_KEY": "your_api_key_here"
|
|
34
|
+
"TRU_API_URL": "https://tru-by29.onrender.com"
|
|
28
35
|
}
|
|
29
36
|
}
|
|
30
37
|
}
|
|
@@ -35,7 +42,7 @@ Add to your `.mcp.json` (Claude Code) or equivalent:
|
|
|
35
42
|
|
|
36
43
|
| Variable | Required | Description |
|
|
37
44
|
|----------|----------|-------------|
|
|
38
|
-
| `TRU_API_KEY` |
|
|
45
|
+
| `TRU_API_KEY` | No | Your tru API key (starts with `tru_ak_`). Not needed for initial setup — `register_app` will create one. |
|
|
39
46
|
| `TRU_API_URL` | No | tru server URL (default: `https://tru-by29.onrender.com`) |
|
|
40
47
|
|
|
41
48
|
## Getting Started
|
|
@@ -56,14 +63,17 @@ After that, you're live. All the tools below work immediately.
|
|
|
56
63
|
| `get_started` | Full setup guide — what tru is, how to integrate, risk signals explained |
|
|
57
64
|
| `register_app` | Register a new app on tru and get an API key |
|
|
58
65
|
| `connect_stripe` | Link your existing Stripe account to receive payments |
|
|
59
|
-
|
|
|
66
|
+
| `discover_api` | Crawl your site and generate an agent skill (SKILL.md) |
|
|
67
|
+
| **Identity & Data** | |
|
|
60
68
|
| `check_identity` | Verify a user + get risk signals (level, score, card funding, country) |
|
|
61
|
-
| `
|
|
69
|
+
| `request_user_data` | Request verified data from a user's vault (name, email, phone, address) |
|
|
62
70
|
| `check_request_status` | Poll the status of a credential request |
|
|
63
71
|
| **Billing** | |
|
|
64
72
|
| `create_charge` | Create a direct charge or subscription |
|
|
65
73
|
| `check_charge_status` | Check the status of a charge request |
|
|
66
74
|
| `request_virtual_card` | Issue a single-use virtual card for agent purchases |
|
|
75
|
+
| **Provisioning** | |
|
|
76
|
+
| `provision_user` | Auto-create a user account on a third-party app |
|
|
67
77
|
| **Discovery** | |
|
|
68
78
|
| `discover_apps` | Browse registered apps on the tru platform |
|
|
69
79
|
| `read_skill` | Read an app's agent skill guide |
|
|
@@ -95,6 +105,20 @@ Agent: Now let's connect your Stripe account.
|
|
|
95
105
|
Agent: You're live. Charges approved by tru users will flow to your Stripe account.
|
|
96
106
|
```
|
|
97
107
|
|
|
108
|
+
## Example: Auto-Provisioning
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
User: Sign me up for clayking
|
|
112
|
+
|
|
113
|
+
Agent: → check_identity(email: "user@example.com")
|
|
114
|
+
✓ Verified — risk: low
|
|
115
|
+
|
|
116
|
+
Agent: → provision_user(email: "user@example.com", service_name: "clayking")
|
|
117
|
+
✓ Provisioned — got API key and account ID
|
|
118
|
+
|
|
119
|
+
Agent: Now using clayking API on behalf of user...
|
|
120
|
+
```
|
|
121
|
+
|
|
98
122
|
## Example: End User Flow
|
|
99
123
|
|
|
100
124
|
```
|
|
@@ -103,7 +127,7 @@ User: Sign me up for that new service
|
|
|
103
127
|
Agent: → check_identity(email: "user@example.com")
|
|
104
128
|
✓ Verified — risk: low, score: 12, debit card, US
|
|
105
129
|
|
|
106
|
-
Agent: →
|
|
130
|
+
Agent: → request_user_data(email: "user@example.com", fields: ["name", "email"])
|
|
107
131
|
⏳ Pending — approve on your tru dashboard
|
|
108
132
|
|
|
109
133
|
Agent: → check_request_status(request_id: "req_abc123")
|
package/dist/api-client.d.ts
CHANGED
|
@@ -79,6 +79,7 @@ export interface RegisterAppParams {
|
|
|
79
79
|
website?: string;
|
|
80
80
|
allowed_fields?: string[];
|
|
81
81
|
redirect_uris?: string[];
|
|
82
|
+
provision_url?: string;
|
|
82
83
|
}
|
|
83
84
|
export interface RegisterAppResponse {
|
|
84
85
|
app: {
|
|
@@ -113,5 +114,22 @@ export interface ConnectOAuthResponse {
|
|
|
113
114
|
payouts_enabled?: boolean;
|
|
114
115
|
}
|
|
115
116
|
export declare function getConnectOAuthUrl(serviceName: string): Promise<ConnectOAuthResponse>;
|
|
117
|
+
export interface DiscoverApiResponse {
|
|
118
|
+
endpoints_found: number;
|
|
119
|
+
pages_crawled: number;
|
|
120
|
+
skill_url: string;
|
|
121
|
+
skill_preview: string;
|
|
122
|
+
}
|
|
123
|
+
export declare function discoverApi(serviceName: string): Promise<DiscoverApiResponse>;
|
|
124
|
+
export interface ProvisionResponse {
|
|
125
|
+
credentials: Record<string, unknown>;
|
|
126
|
+
provisioned: boolean;
|
|
127
|
+
}
|
|
128
|
+
export interface AppCredentialsResponse {
|
|
129
|
+
status: "active" | "not_provisioned";
|
|
130
|
+
credentials?: Record<string, unknown>;
|
|
131
|
+
}
|
|
132
|
+
export declare function provisionUser(email: string, serviceName: string): Promise<ProvisionResponse>;
|
|
133
|
+
export declare function getAppCredentials(email: string, serviceName: string): Promise<AppCredentialsResponse>;
|
|
116
134
|
export declare function requestAgentCard(email: string, amountCents: number, description?: string, targetService?: string, currency?: string, action?: string): Promise<AgentCardResponse>;
|
|
117
135
|
export {};
|
package/dist/api-client.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
const BASE_URL = process.env.TRU_API_URL || "http://localhost:3000";
|
|
2
|
-
|
|
2
|
+
// API key is read dynamically so register_app can set it at runtime
|
|
3
|
+
function getApiKey() {
|
|
4
|
+
return process.env.TRU_API_KEY || "";
|
|
5
|
+
}
|
|
3
6
|
async function request(path, options = {}) {
|
|
4
7
|
const url = `${BASE_URL}${path}`;
|
|
5
8
|
const res = await fetch(url, {
|
|
6
9
|
...options,
|
|
7
10
|
headers: {
|
|
8
11
|
"Content-Type": "application/json",
|
|
9
|
-
"X-API-Key":
|
|
12
|
+
"X-API-Key": getApiKey(),
|
|
10
13
|
...options.headers,
|
|
11
14
|
},
|
|
12
15
|
});
|
|
@@ -62,6 +65,53 @@ export async function getChargeStatus(id) {
|
|
|
62
65
|
export async function getConnectOAuthUrl(serviceName) {
|
|
63
66
|
return (await request(`/api/connect/by-service/${encodeURIComponent(serviceName)}/oauth-url`));
|
|
64
67
|
}
|
|
68
|
+
export async function discoverApi(serviceName) {
|
|
69
|
+
const url = `${BASE_URL}/apps/${encodeURIComponent(serviceName)}/discover`;
|
|
70
|
+
const res = await fetch(url, {
|
|
71
|
+
method: "POST",
|
|
72
|
+
headers: {
|
|
73
|
+
"Content-Type": "application/json",
|
|
74
|
+
"X-API-Key": getApiKey(),
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
if (!res.ok) {
|
|
78
|
+
const body = await res.text();
|
|
79
|
+
throw new Error(`API error ${res.status}: ${body}`);
|
|
80
|
+
}
|
|
81
|
+
// The response is NDJSON — read all lines and extract the final results
|
|
82
|
+
const text = await res.text();
|
|
83
|
+
const lines = text.trim().split("\n");
|
|
84
|
+
let endpointsFound = 0;
|
|
85
|
+
let pagesCrawled = 0;
|
|
86
|
+
let skillContent = "";
|
|
87
|
+
for (const line of lines) {
|
|
88
|
+
try {
|
|
89
|
+
const event = JSON.parse(line);
|
|
90
|
+
if (event.type === "endpoints")
|
|
91
|
+
endpointsFound = event.count;
|
|
92
|
+
if (event.type === "pages")
|
|
93
|
+
pagesCrawled = event.count;
|
|
94
|
+
if (event.type === "skill")
|
|
95
|
+
skillContent = event.content;
|
|
96
|
+
}
|
|
97
|
+
catch { }
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
endpoints_found: endpointsFound,
|
|
101
|
+
pages_crawled: pagesCrawled,
|
|
102
|
+
skill_url: `${BASE_URL}/apps/${encodeURIComponent(serviceName)}/SKILL.md`,
|
|
103
|
+
skill_preview: skillContent.slice(0, 2000),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
export async function provisionUser(email, serviceName) {
|
|
107
|
+
return (await request(`/api/apps/by-service/${encodeURIComponent(serviceName)}/provision`, {
|
|
108
|
+
method: "POST",
|
|
109
|
+
body: JSON.stringify({ email }),
|
|
110
|
+
}));
|
|
111
|
+
}
|
|
112
|
+
export async function getAppCredentials(email, serviceName) {
|
|
113
|
+
return (await request(`/api/apps/by-service/${encodeURIComponent(serviceName)}/credentials/${encodeURIComponent(email)}`));
|
|
114
|
+
}
|
|
65
115
|
export async function requestAgentCard(email, amountCents, description, targetService, currency, action) {
|
|
66
116
|
return (await request("/api/billing/agent-card", {
|
|
67
117
|
method: "POST",
|
package/dist/api-client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"AAAA,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,uBAAuB,CAAC;AACpE,
|
|
1
|
+
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"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"}
|
package/dist/init.js
CHANGED
|
@@ -1,21 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { readFile, writeFile, access } from "node:fs/promises";
|
|
5
|
-
import { join } from "node:path";
|
|
2
|
+
import { readFile, writeFile, access, mkdir } from "node:fs/promises";
|
|
3
|
+
import { join, dirname } from "node:path";
|
|
6
4
|
import { homedir } from "node:os";
|
|
7
5
|
const DEFAULT_URL = "https://tru-by29.onrender.com";
|
|
8
6
|
function detectTargets() {
|
|
9
7
|
const targets = [];
|
|
10
8
|
const cwd = process.cwd();
|
|
11
|
-
// Claude Code — .mcp.json in current directory
|
|
12
|
-
targets.push({
|
|
13
|
-
name: "Claude Code",
|
|
14
|
-
path: join(cwd, ".mcp.json"),
|
|
15
|
-
});
|
|
16
|
-
// Claude Desktop
|
|
17
9
|
const home = homedir();
|
|
18
10
|
const platform = process.platform;
|
|
11
|
+
targets.push({ name: "Claude Code", path: join(cwd, ".mcp.json") });
|
|
19
12
|
if (platform === "darwin") {
|
|
20
13
|
targets.push({
|
|
21
14
|
name: "Claude Desktop",
|
|
@@ -34,119 +27,81 @@ function detectTargets() {
|
|
|
34
27
|
path: join(home, ".config", "Claude", "claude_desktop_config.json"),
|
|
35
28
|
});
|
|
36
29
|
}
|
|
37
|
-
|
|
38
|
-
targets.push({
|
|
39
|
-
name: "Cursor",
|
|
40
|
-
path: join(cwd, ".cursor", "mcp.json"),
|
|
41
|
-
});
|
|
30
|
+
targets.push({ name: "Cursor", path: join(cwd, ".cursor", "mcp.json") });
|
|
42
31
|
return targets;
|
|
43
32
|
}
|
|
44
|
-
async function fileExists(
|
|
33
|
+
async function fileExists(p) {
|
|
45
34
|
try {
|
|
46
|
-
await access(
|
|
35
|
+
await access(p);
|
|
47
36
|
return true;
|
|
48
37
|
}
|
|
49
38
|
catch {
|
|
50
39
|
return false;
|
|
51
40
|
}
|
|
52
41
|
}
|
|
53
|
-
async function readJsonFile(
|
|
42
|
+
async function readJsonFile(p) {
|
|
54
43
|
try {
|
|
55
|
-
const raw = await readFile(
|
|
44
|
+
const raw = await readFile(p, "utf-8");
|
|
56
45
|
return JSON.parse(raw);
|
|
57
46
|
}
|
|
58
47
|
catch {
|
|
59
48
|
return {};
|
|
60
49
|
}
|
|
61
50
|
}
|
|
62
|
-
function
|
|
63
|
-
|
|
51
|
+
function buildEntry(apiKey) {
|
|
52
|
+
const entry = {
|
|
64
53
|
command: "npx",
|
|
65
54
|
args: ["-y", "tru-mcp"],
|
|
66
|
-
env: {
|
|
67
|
-
TRU_API_URL: apiUrl,
|
|
68
|
-
TRU_API_KEY: apiKey,
|
|
69
|
-
},
|
|
70
55
|
};
|
|
56
|
+
if (apiKey) {
|
|
57
|
+
entry.env = { TRU_API_URL: DEFAULT_URL, TRU_API_KEY: apiKey };
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
entry.env = { TRU_API_URL: DEFAULT_URL };
|
|
61
|
+
}
|
|
62
|
+
return entry;
|
|
71
63
|
}
|
|
72
|
-
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
rl.close();
|
|
81
|
-
process.exit(1);
|
|
64
|
+
function parseArgs() {
|
|
65
|
+
const args = process.argv.slice(2).filter((a) => a !== "init");
|
|
66
|
+
let key;
|
|
67
|
+
for (let i = 0; i < args.length; i++) {
|
|
68
|
+
if (args[i] === "--key" && args[i + 1]) {
|
|
69
|
+
key = args[i + 1];
|
|
70
|
+
i++;
|
|
71
|
+
}
|
|
82
72
|
}
|
|
83
|
-
|
|
73
|
+
return { key };
|
|
74
|
+
}
|
|
75
|
+
async function main() {
|
|
76
|
+
const { key } = parseArgs();
|
|
77
|
+
console.log("\n tru MCP — setting up...\n");
|
|
84
78
|
const targets = detectTargets();
|
|
85
|
-
const
|
|
86
|
-
const
|
|
79
|
+
const written = [];
|
|
80
|
+
const entry = buildEntry(key);
|
|
87
81
|
for (const t of targets) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
|
|
82
|
+
// Write to existing config files, or create .mcp.json for Claude Code
|
|
83
|
+
const exists = await fileExists(t.path);
|
|
84
|
+
if (!exists && t.name !== "Claude Code")
|
|
85
|
+
continue;
|
|
86
|
+
// Ensure parent dir exists
|
|
87
|
+
await mkdir(dirname(t.path), { recursive: true });
|
|
88
|
+
const config = exists ? await readJsonFile(t.path) : {};
|
|
89
|
+
if (!config.mcpServers)
|
|
90
|
+
config.mcpServers = {};
|
|
91
|
+
config.mcpServers.tru = entry;
|
|
92
|
+
await writeFile(t.path, JSON.stringify(config, null, 2) + "\n");
|
|
93
|
+
written.push(t.name);
|
|
98
94
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
console.log("\n No MCP client config files detected. Add this to your config:\n");
|
|
103
|
-
printManualConfig(apiUrl, apiKey);
|
|
104
|
-
rl.close();
|
|
95
|
+
if (written.length === 0) {
|
|
96
|
+
console.log(" No MCP client detected. Add this to your config:\n");
|
|
97
|
+
console.log(JSON.stringify({ mcpServers: { tru: entry } }, null, 2) + "\n");
|
|
105
98
|
return;
|
|
106
99
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
available.forEach((t, i) => {
|
|
110
|
-
const tag = existing.includes(t) ? "(existing)" : "(will create)";
|
|
111
|
-
console.log(` ${i + 1}. ${t.name} ${tag} — ${t.path}`);
|
|
112
|
-
});
|
|
113
|
-
const choice = (await rl.question(`\n Configure which? [1-${available.length}, or "all"]: `)).trim();
|
|
114
|
-
let selected;
|
|
115
|
-
if (choice.toLowerCase() === "all") {
|
|
116
|
-
selected = available;
|
|
117
|
-
}
|
|
118
|
-
else {
|
|
119
|
-
const idx = parseInt(choice, 10) - 1;
|
|
120
|
-
if (isNaN(idx) || idx < 0 || idx >= available.length) {
|
|
121
|
-
console.log("\n Invalid choice. Here's the manual config instead:\n");
|
|
122
|
-
printManualConfig(apiUrl, apiKey);
|
|
123
|
-
rl.close();
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
selected = [available[idx]];
|
|
127
|
-
}
|
|
128
|
-
// Write configs
|
|
129
|
-
const entry = buildTruEntry(apiUrl, apiKey);
|
|
130
|
-
for (const target of selected) {
|
|
131
|
-
const config = await readJsonFile(target.path);
|
|
132
|
-
if (!config.mcpServers) {
|
|
133
|
-
config.mcpServers = {};
|
|
134
|
-
}
|
|
135
|
-
config.mcpServers.tru = entry;
|
|
136
|
-
await writeFile(target.path, JSON.stringify(config, null, 2) + "\n");
|
|
137
|
-
console.log(` ✓ Updated ${target.name} — ${target.path}`);
|
|
100
|
+
for (const name of written) {
|
|
101
|
+
console.log(` ✓ ${name}`);
|
|
138
102
|
}
|
|
139
|
-
console.log("\n Done
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
function printManualConfig(apiUrl, apiKey) {
|
|
143
|
-
const snippet = {
|
|
144
|
-
mcpServers: {
|
|
145
|
-
tru: buildTruEntry(apiUrl, apiKey),
|
|
146
|
-
},
|
|
147
|
-
};
|
|
148
|
-
console.log(JSON.stringify(snippet, null, 2));
|
|
149
|
-
console.log();
|
|
103
|
+
console.log("\n Done. Restart your MCP client, then tell your agent:\n");
|
|
104
|
+
console.log(' "Run get_started to set up tru"\n');
|
|
150
105
|
}
|
|
151
106
|
main().catch((err) => {
|
|
152
107
|
console.error("Error:", err);
|
package/dist/init.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
|
package/dist/server.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
3
|
import { checkIdentityTool } from "./tools/check_identity.js";
|
|
4
|
-
import {
|
|
4
|
+
import { requestUserDataTool } from "./tools/request_user_data.js";
|
|
5
5
|
import { checkRequestStatusTool } from "./tools/check_request_status.js";
|
|
6
6
|
import { requestVirtualCardTool } from "./tools/request_virtual_card.js";
|
|
7
7
|
import { discoverAppsTool } from "./tools/discover_apps.js";
|
|
@@ -12,13 +12,15 @@ import { registerAppTool } from "./tools/register_app.js";
|
|
|
12
12
|
import { initiateOAuthTool } from "./tools/initiate_oauth.js";
|
|
13
13
|
import { connectStripeTool } from "./tools/connect_stripe.js";
|
|
14
14
|
import { getStartedTool } from "./tools/get_started.js";
|
|
15
|
+
import { discoverApiTool } from "./tools/discover_api.js";
|
|
16
|
+
import { provisionUserTool } from "./tools/provision_user.js";
|
|
15
17
|
const server = new McpServer({
|
|
16
18
|
name: "tru-identity",
|
|
17
19
|
version: "0.1.0",
|
|
18
20
|
});
|
|
19
21
|
// Register tools
|
|
20
22
|
server.tool(checkIdentityTool.name, checkIdentityTool.description, checkIdentityTool.inputSchema, checkIdentityTool.handler);
|
|
21
|
-
server.tool(
|
|
23
|
+
server.tool(requestUserDataTool.name, requestUserDataTool.description, requestUserDataTool.inputSchema, requestUserDataTool.handler);
|
|
22
24
|
server.tool(checkRequestStatusTool.name, checkRequestStatusTool.description, checkRequestStatusTool.inputSchema, checkRequestStatusTool.handler);
|
|
23
25
|
server.tool(requestVirtualCardTool.name, requestVirtualCardTool.description, requestVirtualCardTool.inputSchema, requestVirtualCardTool.handler);
|
|
24
26
|
server.tool(discoverAppsTool.name, discoverAppsTool.description, discoverAppsTool.inputSchema, discoverAppsTool.handler);
|
|
@@ -29,6 +31,8 @@ server.tool(registerAppTool.name, registerAppTool.description, registerAppTool.i
|
|
|
29
31
|
server.tool(initiateOAuthTool.name, initiateOAuthTool.description, initiateOAuthTool.inputSchema, initiateOAuthTool.handler);
|
|
30
32
|
server.tool(connectStripeTool.name, connectStripeTool.description, connectStripeTool.inputSchema, connectStripeTool.handler);
|
|
31
33
|
server.tool(getStartedTool.name, getStartedTool.description, getStartedTool.inputSchema, getStartedTool.handler);
|
|
34
|
+
server.tool(discoverApiTool.name, discoverApiTool.description, discoverApiTool.inputSchema, discoverApiTool.handler);
|
|
35
|
+
server.tool(provisionUserTool.name, provisionUserTool.description, provisionUserTool.inputSchema, provisionUserTool.handler);
|
|
32
36
|
export async function run() {
|
|
33
37
|
const transport = new StdioServerTransport();
|
|
34
38
|
await server.connect(transport);
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const discoverApiTool: {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
inputSchema: {
|
|
6
|
+
service_name: z.ZodString;
|
|
7
|
+
};
|
|
8
|
+
handler: (args: {
|
|
9
|
+
service_name: string;
|
|
10
|
+
}) => Promise<{
|
|
11
|
+
content: {
|
|
12
|
+
type: "text";
|
|
13
|
+
text: string;
|
|
14
|
+
}[];
|
|
15
|
+
isError?: undefined;
|
|
16
|
+
} | {
|
|
17
|
+
content: {
|
|
18
|
+
type: "text";
|
|
19
|
+
text: string;
|
|
20
|
+
}[];
|
|
21
|
+
isError: boolean;
|
|
22
|
+
}>;
|
|
23
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { discoverApi, lookupAppByServiceName } from "../api-client.js";
|
|
3
|
+
export const discoverApiTool = {
|
|
4
|
+
name: "discover_api",
|
|
5
|
+
description: "Crawl a registered app's website to discover its API endpoints, documentation, and developer guides. " +
|
|
6
|
+
"Generates an agent skill (SKILL.md) that teaches AI agents how to use the app. " +
|
|
7
|
+
"The app must have a website URL set. Call this after register_app to make your app agent-friendly.",
|
|
8
|
+
inputSchema: {
|
|
9
|
+
service_name: z
|
|
10
|
+
.string()
|
|
11
|
+
.describe("The service_name of the app to discover (e.g. 'my-app')"),
|
|
12
|
+
},
|
|
13
|
+
handler: async (args) => {
|
|
14
|
+
try {
|
|
15
|
+
// Verify the app exists first
|
|
16
|
+
const lookup = await lookupAppByServiceName(args.service_name);
|
|
17
|
+
if (lookup.status === "not_found") {
|
|
18
|
+
return {
|
|
19
|
+
content: [
|
|
20
|
+
{
|
|
21
|
+
type: "text",
|
|
22
|
+
text: `App "${args.service_name}" not found. Use register_app to create it first.`,
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const result = await discoverApi(args.service_name);
|
|
28
|
+
const lines = [
|
|
29
|
+
`API discovery complete for "${args.service_name}".`,
|
|
30
|
+
``,
|
|
31
|
+
`Pages crawled: ${result.pages_crawled}`,
|
|
32
|
+
`API endpoints found: ${result.endpoints_found}`,
|
|
33
|
+
``,
|
|
34
|
+
`Generated agent skill available at:`,
|
|
35
|
+
`${result.skill_url}`,
|
|
36
|
+
``,
|
|
37
|
+
`Any AI agent can now fetch this skill to learn how to sign up, authenticate, and use your app's API.`,
|
|
38
|
+
``,
|
|
39
|
+
`To view the full skill: use the read_skill tool with service_name "${args.service_name}".`,
|
|
40
|
+
];
|
|
41
|
+
if (result.endpoints_found === 0) {
|
|
42
|
+
lines.push(``, `No API endpoints were auto-detected. To improve discovery:`, `- Add an /openapi.json or /swagger.json file to your app`, `- Add an /agent.md file with your API documentation`, `- Make sure your /docs or /api/docs pages are publicly accessible`, `- Or edit the skill manually in the tru dashboard`);
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
50
|
+
if (message.includes("website URL")) {
|
|
51
|
+
return {
|
|
52
|
+
content: [
|
|
53
|
+
{
|
|
54
|
+
type: "text",
|
|
55
|
+
text: `App "${args.service_name}" doesn't have a website URL set. Ask the developer for their domain and update the app:\n\nPUT /api/apps/:id with { "website": "https://their-domain.com" }\n\nOr re-register with the website field included.`,
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
isError: true,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
content: [
|
|
63
|
+
{
|
|
64
|
+
type: "text",
|
|
65
|
+
text: `Error discovering API: ${message}`,
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
isError: true,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=discover_api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discover_api.js","sourceRoot":"","sources":["../../src/tools/discover_api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAEvE,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,IAAI,EAAE,cAAc;IACpB,WAAW,EACT,uGAAuG;QACvG,iFAAiF;QACjF,oGAAoG;IACtG,WAAW,EAAE;QACX,YAAY,EAAE,CAAC;aACZ,MAAM,EAAE;aACR,QAAQ,CAAC,yDAAyD,CAAC;KACvE;IACD,OAAO,EAAE,KAAK,EAAE,IAA8B,EAAE,EAAE;QAChD,IAAI,CAAC;YACH,8BAA8B;YAC9B,MAAM,MAAM,GAAG,MAAM,sBAAsB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAC/D,IAAI,MAAM,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;gBAClC,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE,QAAQ,IAAI,CAAC,YAAY,mDAAmD;yBACnF;qBACF;iBACF,CAAC;YACJ,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAEpD,MAAM,KAAK,GAAG;gBACZ,+BAA+B,IAAI,CAAC,YAAY,IAAI;gBACpD,EAAE;gBACF,kBAAkB,MAAM,CAAC,aAAa,EAAE;gBACxC,wBAAwB,MAAM,CAAC,eAAe,EAAE;gBAChD,EAAE;gBACF,qCAAqC;gBACrC,GAAG,MAAM,CAAC,SAAS,EAAE;gBACrB,EAAE;gBACF,sGAAsG;gBACtG,EAAE;gBACF,sEAAsE,IAAI,CAAC,YAAY,IAAI;aAC5F,CAAC;YAEF,IAAI,MAAM,CAAC,eAAe,KAAK,CAAC,EAAE,CAAC;gBACjC,KAAK,CAAC,IAAI,CACR,EAAE,EACF,4DAA4D,EAC5D,0DAA0D,EAC1D,qDAAqD,EACrD,mEAAmE,EACnE,mDAAmD,CACpD,CAAC;YACJ,CAAC;YAED,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;aAC7D,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAEjE,IAAI,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;gBACpC,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE,QAAQ,IAAI,CAAC,YAAY,iNAAiN;yBACjP;qBACF;oBACD,OAAO,EAAE,IAAI;iBACd,CAAC;YACJ,CAAC;YAED,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,0BAA0B,OAAO,EAAE;qBAC1C;iBACF;gBACD,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC;CACF,CAAC"}
|
|
@@ -2,8 +2,8 @@ export const getStartedTool = {
|
|
|
2
2
|
name: "get_started",
|
|
3
3
|
description: "Returns a complete guide for developers integrating tru into their app. " +
|
|
4
4
|
"Covers what tru is (auth + billing API with risk signals), why it matters, " +
|
|
5
|
-
"and walks through setup step-by-step using the MCP tools: register_app, connect_stripe, " +
|
|
6
|
-
"and then using create_charge,
|
|
5
|
+
"and walks through setup step-by-step using the MCP tools: register_app, connect_stripe, discover_api, " +
|
|
6
|
+
"and then using create_charge, request_user_data, and check_identity. " +
|
|
7
7
|
"Call this first when a developer wants to integrate tru.",
|
|
8
8
|
inputSchema: {},
|
|
9
9
|
handler: async (_args) => {
|
|
@@ -51,10 +51,14 @@ register_app(
|
|
|
51
51
|
)
|
|
52
52
|
\`\`\`
|
|
53
53
|
|
|
54
|
-
This creates your app on tru and returns an **API key** (starts with \`tru_ak_\`).
|
|
54
|
+
This creates your app on tru and returns an **API key** (starts with \`tru_ak_\`). The key is automatically:
|
|
55
|
+
- **Set for this session** — all subsequent tru tools work immediately
|
|
56
|
+
- **Saved to your MCP config** — future sessions pick it up without manual steps
|
|
55
57
|
|
|
56
58
|
The \`service_name\` is your app's unique identifier on tru (lowercase, letters/numbers/hyphens).
|
|
57
59
|
|
|
60
|
+
**Important:** Always ask the developer for their \`website\` URL. tru uses it to crawl their docs and generate an agent skill (Step 3), and it's needed for the agent widget (Step 4). Without it, agents won't be able to discover the app.
|
|
61
|
+
|
|
58
62
|
### Step 2: Connect your Stripe account
|
|
59
63
|
|
|
60
64
|
\`\`\`
|
|
@@ -72,12 +76,40 @@ This generates a URL. Open it in your browser, log into your existing Stripe acc
|
|
|
72
76
|
|
|
73
77
|
**If you don't have a Stripe account yet**, the OAuth flow will let you create one. But most developers already have one, and the whole point is that nothing about it changes.
|
|
74
78
|
|
|
75
|
-
### Step 3:
|
|
79
|
+
### Step 3: Discover your API
|
|
80
|
+
|
|
81
|
+
\`\`\`
|
|
82
|
+
discover_api(service_name: "my-app")
|
|
83
|
+
\`\`\`
|
|
84
|
+
|
|
85
|
+
tru will crawl your website — homepage, docs pages, API references, OpenAPI specs — and generate a **SKILL.md** that teaches AI agents how to use your app. The more docs you have publicly accessible, the better the generated skill.
|
|
86
|
+
|
|
87
|
+
**Tips for better discovery:**
|
|
88
|
+
- Serve an \`/openapi.json\` or \`/swagger.json\` for structured endpoint detection
|
|
89
|
+
- Add an \`/agent.md\` with custom agent instructions
|
|
90
|
+
- Make your \`/docs\` pages publicly accessible (no auth wall on docs)
|
|
91
|
+
- You can also edit the generated skill in the tru dashboard
|
|
92
|
+
|
|
93
|
+
### Step 4: Add the agent widget
|
|
94
|
+
|
|
95
|
+
Add this script tag to your app's HTML (in \`<head>\` or before \`</body>\`):
|
|
96
|
+
|
|
97
|
+
\`\`\`html
|
|
98
|
+
<script src="https://tru-by29.onrender.com/widget/agent.js" data-app="my-app" defer></script>
|
|
99
|
+
\`\`\`
|
|
100
|
+
|
|
101
|
+
Replace \`my-app\` with your \`service_name\`. This does two things:
|
|
102
|
+
- **For AI agents** visiting your site: shows them a link to your SKILL.md so they know how to use your app (sign up, authenticate, call your API)
|
|
103
|
+
- **For humans**: shows a subtle "agent guide" link
|
|
104
|
+
|
|
105
|
+
This is how agents discover your app's capabilities when they land on your site. Without it, they have to be told about your app explicitly.
|
|
106
|
+
|
|
107
|
+
### Step 5: You're live
|
|
76
108
|
|
|
77
109
|
That's it. Your app can now:
|
|
78
110
|
|
|
79
111
|
- **Verify users** — \`check_identity(email)\` returns whether they're verified, plus risk signals
|
|
80
|
-
- **Request credentials** — \`
|
|
112
|
+
- **Request credentials** — \`request_user_data(email, service, fields)\` asks the user to share verified data
|
|
81
113
|
- **Charge users** — \`create_charge(email, amount_cents, description)\` creates a charge that the user approves
|
|
82
114
|
- **Issue virtual cards** — \`request_virtual_card(email, amount_cents)\` for agent purchases on other sites
|
|
83
115
|
- **Check risk** — every identity check includes risk level, score, card funding type, country, and fingerprint reuse
|
|
@@ -121,10 +153,75 @@ These signals come from Stripe's Radar and Identity — the same fraud detection
|
|
|
121
153
|
|
|
122
154
|
---
|
|
123
155
|
|
|
156
|
+
## Auto-provisioning: Let tru users fly through signup
|
|
157
|
+
|
|
158
|
+
The biggest conversion killer is making users create yet another account on your app. tru solves this with **provisioning** — you add a single endpoint, and tru automatically creates accounts for verified users.
|
|
159
|
+
|
|
160
|
+
### How it works
|
|
161
|
+
|
|
162
|
+
1. Register a \`provision_url\` on your app (via \`register_app\` or the dashboard)
|
|
163
|
+
2. When an agent calls \`provision_user(email, service_name)\`, tru:
|
|
164
|
+
- Verifies the user's identity
|
|
165
|
+
- POSTs their verified info to your \`provision_url\`
|
|
166
|
+
- Stores the credentials you return
|
|
167
|
+
3. The agent gets back API keys / account IDs and can use your service immediately
|
|
168
|
+
|
|
169
|
+
The user never fills out a signup form, never verifies their email (tru already did that), and never hunts for an API key page.
|
|
170
|
+
|
|
171
|
+
### Your provision endpoint
|
|
172
|
+
|
|
173
|
+
tru sends a signed POST request:
|
|
174
|
+
|
|
175
|
+
\`\`\`
|
|
176
|
+
POST {your_provision_url}
|
|
177
|
+
Headers:
|
|
178
|
+
Content-Type: application/json
|
|
179
|
+
X-Tru-Signature: {HMAC-SHA256 of body using your webhook_secret}
|
|
180
|
+
X-Tru-Event: user.provision
|
|
181
|
+
|
|
182
|
+
Body:
|
|
183
|
+
{ "email": "user@example.com", "name": "Jane Doe", "tru_user_id": "user@example.com" }
|
|
184
|
+
\`\`\`
|
|
185
|
+
|
|
186
|
+
Your endpoint should:
|
|
187
|
+
1. Create an account for the user (or find existing)
|
|
188
|
+
2. Generate an API key or credentials
|
|
189
|
+
3. Return them as JSON (any shape — tru stores the whole response)
|
|
190
|
+
|
|
191
|
+
\`\`\`json
|
|
192
|
+
{ "api_key": "sk_live_abc123", "account_id": "acct_xyz" }
|
|
193
|
+
\`\`\`
|
|
194
|
+
|
|
195
|
+
### Verify the signature
|
|
196
|
+
|
|
197
|
+
Use your app's \`webhook_secret\` to verify the \`X-Tru-Signature\` header:
|
|
198
|
+
|
|
199
|
+
\`\`\`javascript
|
|
200
|
+
const crypto = require('crypto');
|
|
201
|
+
const expected = crypto.createHmac('sha256', WEBHOOK_SECRET).update(rawBody).digest('hex');
|
|
202
|
+
if (signature !== expected) return res.status(401).json({ error: 'Invalid signature' });
|
|
203
|
+
\`\`\`
|
|
204
|
+
|
|
205
|
+
### Example: register with provisioning
|
|
206
|
+
|
|
207
|
+
\`\`\`
|
|
208
|
+
register_app(
|
|
209
|
+
service_name: "my-app",
|
|
210
|
+
display_name: "My App",
|
|
211
|
+
owner_email: "dev@example.com",
|
|
212
|
+
provision_url: "https://myapp.com/api/tru/provision"
|
|
213
|
+
)
|
|
214
|
+
\`\`\`
|
|
215
|
+
|
|
216
|
+
Then any tru agent can:
|
|
217
|
+
\`\`\`
|
|
218
|
+
provision_user(email: "user@example.com", service_name: "my-app")
|
|
219
|
+
→ { api_key: "sk_live_abc123", account_id: "acct_xyz" }
|
|
220
|
+
\`\`\`
|
|
221
|
+
|
|
124
222
|
## What's next
|
|
125
223
|
|
|
126
224
|
- **Set up webhooks** — get notified when charges are approved/rejected, credentials shared, etc.
|
|
127
|
-
- **Write an Agent Skill** — a SKILL.md that teaches AI agents how to use your app (tru hosts it for you)
|
|
128
225
|
- **Configure App Rules** — users can set per-app spending rules; you can set default limits on your side
|
|
129
226
|
- **Add "Login with tru"** — OAuth 2.0 flow for browser-based auth (see integration docs)
|
|
130
227
|
|
|
@@ -135,12 +232,14 @@ These signals come from Stripe's Radar and Identity — the same fraud detection
|
|
|
135
232
|
| \`get_started\` | This guide |
|
|
136
233
|
| \`register_app\` | Create your app, get API key |
|
|
137
234
|
| \`connect_stripe\` | Link your Stripe account |
|
|
235
|
+
| \`discover_api\` | Crawl your site, generate agent skill |
|
|
138
236
|
| \`check_identity\` | Verify a user + get risk signals |
|
|
139
|
-
| \`
|
|
237
|
+
| \`request_user_data\` | Ask user to share verified data |
|
|
140
238
|
| \`check_request_status\` | Poll credential request status |
|
|
141
239
|
| \`create_charge\` | Charge a user (one-time or subscription) |
|
|
142
240
|
| \`check_charge_status\` | Poll charge status |
|
|
143
241
|
| \`request_virtual_card\` | Issue single-use card for agent purchases |
|
|
242
|
+
| \`provision_user\` | Auto-create account on a third-party app |
|
|
144
243
|
| \`discover_apps\` | Browse tru app directory |
|
|
145
244
|
| \`read_skill\` | Read an app's agent guide |
|
|
146
245
|
| \`initiate_oauth\` | Start OAuth login flow |
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get_started.js","sourceRoot":"","sources":["../../src/tools/get_started.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,IAAI,EAAE,aAAa;IACnB,WAAW,EACT,0EAA0E;QAC1E,6EAA6E;QAC7E,
|
|
1
|
+
{"version":3,"file":"get_started.js","sourceRoot":"","sources":["../../src/tools/get_started.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,IAAI,EAAE,aAAa;IACnB,WAAW,EACT,0EAA0E;QAC1E,6EAA6E;QAC7E,wGAAwG;QACxG,uEAAuE;QACvE,0DAA0D;IAC5D,WAAW,EAAE,EAAE;IACf,OAAO,EAAE,KAAK,EAAE,KAA4B,EAAE,EAAE;QAC9C,MAAM,KAAK,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4OjB,CAAC;QAEE,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;SAClD,CAAC;IACJ,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const provisionUserTool: {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
inputSchema: {
|
|
6
|
+
email: z.ZodString;
|
|
7
|
+
service_name: z.ZodString;
|
|
8
|
+
};
|
|
9
|
+
handler: (args: {
|
|
10
|
+
email: string;
|
|
11
|
+
service_name: string;
|
|
12
|
+
}) => Promise<{
|
|
13
|
+
content: {
|
|
14
|
+
type: "text";
|
|
15
|
+
text: string;
|
|
16
|
+
}[];
|
|
17
|
+
isError: boolean;
|
|
18
|
+
} | {
|
|
19
|
+
content: {
|
|
20
|
+
type: "text";
|
|
21
|
+
text: string;
|
|
22
|
+
}[];
|
|
23
|
+
isError?: undefined;
|
|
24
|
+
}>;
|
|
25
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { checkIdentity, provisionUser } from "../api-client.js";
|
|
3
|
+
export const provisionUserTool = {
|
|
4
|
+
name: "provision_user",
|
|
5
|
+
description: "Provision a tru user on a third-party app. The app must have a provision_url configured. " +
|
|
6
|
+
"tru sends the user's verified identity to the app's provision endpoint, the app creates an account " +
|
|
7
|
+
"and returns credentials (API key, account ID, etc.), and tru stores them. " +
|
|
8
|
+
"Returns the credentials so the agent can use the service immediately. " +
|
|
9
|
+
"If the user was already provisioned, returns the stored credentials without hitting the app again.",
|
|
10
|
+
inputSchema: {
|
|
11
|
+
email: z
|
|
12
|
+
.string()
|
|
13
|
+
.describe("Email address of the tru user to provision"),
|
|
14
|
+
service_name: z
|
|
15
|
+
.string()
|
|
16
|
+
.describe("The service_name of the app to provision the user on"),
|
|
17
|
+
},
|
|
18
|
+
handler: async (args) => {
|
|
19
|
+
try {
|
|
20
|
+
// First verify the user exists on tru
|
|
21
|
+
const identity = await checkIdentity(args.email);
|
|
22
|
+
if (!identity.verified) {
|
|
23
|
+
return {
|
|
24
|
+
content: [
|
|
25
|
+
{
|
|
26
|
+
type: "text",
|
|
27
|
+
text: `User ${args.email} is not verified on tru (reason: ${identity.reason || "unknown"}). They need to sign up at tru first.`,
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
isError: true,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
// Call the provision API
|
|
34
|
+
const result = await provisionUser(args.email, args.service_name);
|
|
35
|
+
const lines = [
|
|
36
|
+
result.provisioned
|
|
37
|
+
? `Successfully provisioned ${args.email} on ${args.service_name}.`
|
|
38
|
+
: `${args.email} was already provisioned on ${args.service_name}. Returning stored credentials.`,
|
|
39
|
+
``,
|
|
40
|
+
`Credentials:`,
|
|
41
|
+
`\`\`\`json`,
|
|
42
|
+
JSON.stringify(result.credentials, null, 2),
|
|
43
|
+
`\`\`\``,
|
|
44
|
+
``,
|
|
45
|
+
`Use these credentials to make API calls to ${args.service_name} on behalf of the user.`,
|
|
46
|
+
];
|
|
47
|
+
return {
|
|
48
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
53
|
+
if (message.includes("no provision_url")) {
|
|
54
|
+
return {
|
|
55
|
+
content: [
|
|
56
|
+
{
|
|
57
|
+
type: "text",
|
|
58
|
+
text: [
|
|
59
|
+
`The app "${args.service_name}" doesn't have a provision_url configured.`,
|
|
60
|
+
``,
|
|
61
|
+
`The app developer needs to:`,
|
|
62
|
+
`1. Add a POST endpoint that accepts { email, name, tru_user_id } and returns credentials (e.g. { api_key, account_id })`,
|
|
63
|
+
`2. Register the endpoint URL as provision_url on their tru app settings`,
|
|
64
|
+
``,
|
|
65
|
+
`See the tru developer docs for the full provisioning spec.`,
|
|
66
|
+
].join("\n"),
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
isError: true,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
content: [
|
|
74
|
+
{
|
|
75
|
+
type: "text",
|
|
76
|
+
text: `Error provisioning user: ${message}`,
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
isError: true,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
//# sourceMappingURL=provision_user.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provision_user.js","sourceRoot":"","sources":["../../src/tools/provision_user.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEhE,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,IAAI,EAAE,gBAAgB;IACtB,WAAW,EACT,2FAA2F;QAC3F,qGAAqG;QACrG,4EAA4E;QAC5E,wEAAwE;QACxE,oGAAoG;IACtG,WAAW,EAAE;QACX,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,QAAQ,CAAC,4CAA4C,CAAC;QACzD,YAAY,EAAE,CAAC;aACZ,MAAM,EAAE;aACR,QAAQ,CAAC,sDAAsD,CAAC;KACpE;IACD,OAAO,EAAE,KAAK,EAAE,IAA6C,EAAE,EAAE;QAC/D,IAAI,CAAC;YACH,sCAAsC;YACtC,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACjD,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;gBACvB,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE,QAAQ,IAAI,CAAC,KAAK,oCAAoC,QAAQ,CAAC,MAAM,IAAI,SAAS,uCAAuC;yBAChI;qBACF;oBACD,OAAO,EAAE,IAAI;iBACd,CAAC;YACJ,CAAC;YAED,yBAAyB;YACzB,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;YAElE,MAAM,KAAK,GAAG;gBACZ,MAAM,CAAC,WAAW;oBAChB,CAAC,CAAC,4BAA4B,IAAI,CAAC,KAAK,OAAO,IAAI,CAAC,YAAY,GAAG;oBACnE,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,+BAA+B,IAAI,CAAC,YAAY,iCAAiC;gBAClG,EAAE;gBACF,cAAc;gBACd,YAAY;gBACZ,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC3C,QAAQ;gBACR,EAAE;gBACF,8CAA8C,IAAI,CAAC,YAAY,yBAAyB;aACzF,CAAC;YAEF,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;aAC7D,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAEjE,IAAI,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;gBACzC,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE;gCACJ,YAAY,IAAI,CAAC,YAAY,4CAA4C;gCACzE,EAAE;gCACF,6BAA6B;gCAC7B,yHAAyH;gCACzH,yEAAyE;gCACzE,EAAE;gCACF,4DAA4D;6BAC7D,CAAC,IAAI,CAAC,IAAI,CAAC;yBACb;qBACF;oBACD,OAAO,EAAE,IAAI;iBACd,CAAC;YACJ,CAAC;YAED,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,4BAA4B,OAAO,EAAE;qBAC5C;iBACF;gBACD,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC;CACF,CAAC"}
|
|
@@ -10,6 +10,7 @@ export declare const registerAppTool: {
|
|
|
10
10
|
website: z.ZodOptional<z.ZodString>;
|
|
11
11
|
allowed_fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
12
12
|
redirect_uris: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
13
|
+
provision_url: z.ZodOptional<z.ZodString>;
|
|
13
14
|
};
|
|
14
15
|
handler: (args: {
|
|
15
16
|
service_name: string;
|
|
@@ -19,6 +20,7 @@ export declare const registerAppTool: {
|
|
|
19
20
|
website?: string;
|
|
20
21
|
allowed_fields?: string[];
|
|
21
22
|
redirect_uris?: string[];
|
|
23
|
+
provision_url?: string;
|
|
22
24
|
}) => Promise<{
|
|
23
25
|
content: {
|
|
24
26
|
type: "text";
|
|
@@ -1,9 +1,46 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { readFile, writeFile, access } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { homedir } from "node:os";
|
|
2
5
|
import { registerApp } from "../api-client.js";
|
|
6
|
+
/** Find and update tru API key in MCP config files */
|
|
7
|
+
async function persistApiKey(apiKey) {
|
|
8
|
+
const cwd = process.cwd();
|
|
9
|
+
const home = homedir();
|
|
10
|
+
const platform = process.platform;
|
|
11
|
+
const paths = [
|
|
12
|
+
join(cwd, ".mcp.json"),
|
|
13
|
+
join(cwd, ".cursor", "mcp.json"),
|
|
14
|
+
platform === "darwin"
|
|
15
|
+
? join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json")
|
|
16
|
+
: platform === "win32"
|
|
17
|
+
? join(home, "AppData", "Roaming", "Claude", "claude_desktop_config.json")
|
|
18
|
+
: join(home, ".config", "Claude", "claude_desktop_config.json"),
|
|
19
|
+
];
|
|
20
|
+
const updated = [];
|
|
21
|
+
for (const p of paths) {
|
|
22
|
+
try {
|
|
23
|
+
await access(p);
|
|
24
|
+
const raw = await readFile(p, "utf-8");
|
|
25
|
+
const config = JSON.parse(raw);
|
|
26
|
+
if (config.mcpServers?.tru) {
|
|
27
|
+
if (!config.mcpServers.tru.env)
|
|
28
|
+
config.mcpServers.tru.env = {};
|
|
29
|
+
config.mcpServers.tru.env.TRU_API_KEY = apiKey;
|
|
30
|
+
await writeFile(p, JSON.stringify(config, null, 2) + "\n");
|
|
31
|
+
updated.push(p);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// File doesn't exist or isn't valid JSON — skip
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return updated;
|
|
39
|
+
}
|
|
3
40
|
export const registerAppTool = {
|
|
4
41
|
name: "register_app",
|
|
5
42
|
description: "[Developer tool] Register a new app on the tru platform. This is for developers integrating tru into their service — not for end users. " +
|
|
6
|
-
"Returns an API key
|
|
43
|
+
"Returns an API key and automatically configures it for this session and in MCP config files.",
|
|
7
44
|
inputSchema: {
|
|
8
45
|
service_name: z
|
|
9
46
|
.string()
|
|
@@ -21,7 +58,7 @@ export const registerAppTool = {
|
|
|
21
58
|
website: z
|
|
22
59
|
.string()
|
|
23
60
|
.optional()
|
|
24
|
-
.describe("The app's public URL"),
|
|
61
|
+
.describe("The app's public URL. Required for API discovery (discover_api) and the agent widget. Always ask the developer for this."),
|
|
25
62
|
allowed_fields: z
|
|
26
63
|
.array(z.string())
|
|
27
64
|
.optional()
|
|
@@ -30,27 +67,39 @@ export const registerAppTool = {
|
|
|
30
67
|
.array(z.string())
|
|
31
68
|
.optional()
|
|
32
69
|
.describe("OAuth redirect URIs for the app"),
|
|
70
|
+
provision_url: z
|
|
71
|
+
.string()
|
|
72
|
+
.optional()
|
|
73
|
+
.describe("URL of your provision endpoint. tru POSTs { email, name, tru_user_id } here to auto-create accounts for tru users."),
|
|
33
74
|
},
|
|
34
75
|
handler: async (args) => {
|
|
35
76
|
try {
|
|
36
77
|
const result = await registerApp(args);
|
|
78
|
+
// Set key in-memory so subsequent tools work without restart
|
|
79
|
+
process.env.TRU_API_KEY = result.api_key;
|
|
80
|
+
// Persist key to MCP config files for future sessions
|
|
81
|
+
const configsUpdated = await persistApiKey(result.api_key);
|
|
82
|
+
const lines = [
|
|
83
|
+
`App registered successfully.`,
|
|
84
|
+
``,
|
|
85
|
+
`App ID: ${result.app.id}`,
|
|
86
|
+
`Service name: ${result.app.service_name}`,
|
|
87
|
+
`Display name: ${result.app.display_name}`,
|
|
88
|
+
`Status: ${result.app.status}`,
|
|
89
|
+
``,
|
|
90
|
+
`API Key: ${result.api_key}`,
|
|
91
|
+
];
|
|
92
|
+
if (configsUpdated.length > 0) {
|
|
93
|
+
lines.push(``, `API key auto-saved to:`, ...configsUpdated.map((p) => ` ${p}`), ``, `This session is already configured. Future sessions will pick up the key automatically.`);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
lines.push(``, `This session is configured. To persist the key for future sessions, add TRU_API_KEY to your MCP config.`);
|
|
97
|
+
}
|
|
37
98
|
return {
|
|
38
99
|
content: [
|
|
39
100
|
{
|
|
40
101
|
type: "text",
|
|
41
|
-
text:
|
|
42
|
-
`App registered successfully.`,
|
|
43
|
-
``,
|
|
44
|
-
`App ID: ${result.app.id}`,
|
|
45
|
-
`Service name: ${result.app.service_name}`,
|
|
46
|
-
`Display name: ${result.app.display_name}`,
|
|
47
|
-
`Status: ${result.app.status}`,
|
|
48
|
-
``,
|
|
49
|
-
`API Key: ${result.api_key}`,
|
|
50
|
-
``,
|
|
51
|
-
`WARNING: Save this API key now — it cannot be retrieved later.`,
|
|
52
|
-
`Use it as TRU_API_KEY when configuring the tru MCP server or REST API.`,
|
|
53
|
-
].join("\n"),
|
|
102
|
+
text: lines.join("\n"),
|
|
54
103
|
},
|
|
55
104
|
],
|
|
56
105
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register_app.js","sourceRoot":"","sources":["../../src/tools/register_app.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,IAAI,EAAE,cAAc;IACpB,WAAW,EACT,0IAA0I;QAC1I,
|
|
1
|
+
{"version":3,"file":"register_app.js","sourceRoot":"","sources":["../../src/tools/register_app.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const requestUserDataTool: {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
inputSchema: {
|
|
6
|
+
email: z.ZodString;
|
|
7
|
+
service: z.ZodString;
|
|
8
|
+
fields: z.ZodArray<z.ZodString>;
|
|
9
|
+
};
|
|
10
|
+
handler: (args: {
|
|
11
|
+
email: string;
|
|
12
|
+
service: string;
|
|
13
|
+
fields: string[];
|
|
14
|
+
}) => Promise<{
|
|
15
|
+
content: {
|
|
16
|
+
type: "text";
|
|
17
|
+
text: string;
|
|
18
|
+
}[];
|
|
19
|
+
isError?: undefined;
|
|
20
|
+
} | {
|
|
21
|
+
content: {
|
|
22
|
+
type: "text";
|
|
23
|
+
text: string;
|
|
24
|
+
}[];
|
|
25
|
+
isError: boolean;
|
|
26
|
+
}>;
|
|
27
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { checkIdentity, requestCredentials } from "../api-client.js";
|
|
3
|
+
export const requestUserDataTool = {
|
|
4
|
+
name: "request_user_data",
|
|
5
|
+
description: "Request verified data from a tru user (name, email, phone, address, banking). The user will be notified and must approve the request on their dashboard.",
|
|
6
|
+
inputSchema: {
|
|
7
|
+
email: z.string().describe("Email address of the tru user"),
|
|
8
|
+
service: z.string().describe("Name of the service requesting data"),
|
|
9
|
+
fields: z
|
|
10
|
+
.array(z.string())
|
|
11
|
+
.describe("List of fields to request, e.g. ['name', 'email', 'phone', 'address', 'banking']"),
|
|
12
|
+
},
|
|
13
|
+
handler: async (args) => {
|
|
14
|
+
try {
|
|
15
|
+
// First check if the user exists and is verified
|
|
16
|
+
const identity = await checkIdentity(args.email);
|
|
17
|
+
if (!identity.verified) {
|
|
18
|
+
const reason = identity.reason === "user_not_found"
|
|
19
|
+
? "No tru account found for this email."
|
|
20
|
+
: identity.reason === "not_verified"
|
|
21
|
+
? "This user has not completed tru identity verification."
|
|
22
|
+
: identity.reason === "no_vault"
|
|
23
|
+
? "This user's credential vault is not populated."
|
|
24
|
+
: `User is not verified (${identity.reason}).`;
|
|
25
|
+
return {
|
|
26
|
+
content: [
|
|
27
|
+
{
|
|
28
|
+
type: "text",
|
|
29
|
+
text: `Cannot request user data: ${reason}`,
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
// User is verified — create the data request
|
|
35
|
+
const request = await requestCredentials(args.email, args.service, args.fields);
|
|
36
|
+
const lines = [
|
|
37
|
+
`User data request created successfully.`,
|
|
38
|
+
``,
|
|
39
|
+
`Request ID: ${request.id}`,
|
|
40
|
+
`User: ${args.email}`,
|
|
41
|
+
`Service: ${args.service}`,
|
|
42
|
+
`Fields requested: ${args.fields.join(", ")}`,
|
|
43
|
+
`Status: pending`,
|
|
44
|
+
``,
|
|
45
|
+
`The user has been notified and must approve this request on their tru dashboard.`,
|
|
46
|
+
`Use the check_request_status tool with request ID "${request.id}" to check if the user has responded.`,
|
|
47
|
+
];
|
|
48
|
+
return {
|
|
49
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
54
|
+
return {
|
|
55
|
+
content: [
|
|
56
|
+
{ type: "text", text: `Error requesting user data: ${message}` },
|
|
57
|
+
],
|
|
58
|
+
isError: true,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
//# sourceMappingURL=request_user_data.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request_user_data.js","sourceRoot":"","sources":["../../src/tools/request_user_data.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAErE,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,IAAI,EAAE,mBAAmB;IACzB,WAAW,EACT,0JAA0J;IAC5J,WAAW,EAAE;QACX,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;QAC3D,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qCAAqC,CAAC;QACnE,MAAM,EAAE,CAAC;aACN,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;aACjB,QAAQ,CACP,kFAAkF,CACnF;KACJ;IACD,OAAO,EAAE,KAAK,EAAE,IAA0D,EAAE,EAAE;QAC5E,IAAI,CAAC;YACH,iDAAiD;YACjD,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAEjD,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;gBACvB,MAAM,MAAM,GACV,QAAQ,CAAC,MAAM,KAAK,gBAAgB;oBAClC,CAAC,CAAC,sCAAsC;oBACxC,CAAC,CAAC,QAAQ,CAAC,MAAM,KAAK,cAAc;wBAClC,CAAC,CAAC,wDAAwD;wBAC1D,CAAC,CAAC,QAAQ,CAAC,MAAM,KAAK,UAAU;4BAC9B,CAAC,CAAC,gDAAgD;4BAClD,CAAC,CAAC,yBAAyB,QAAQ,CAAC,MAAM,IAAI,CAAC;gBAEvD,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE,6BAA6B,MAAM,EAAE;yBAC5C;qBACF;iBACF,CAAC;YACJ,CAAC;YAED,6CAA6C;YAC7C,MAAM,OAAO,GAAG,MAAM,kBAAkB,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YAEhF,MAAM,KAAK,GAAG;gBACZ,yCAAyC;gBACzC,EAAE;gBACF,eAAe,OAAO,CAAC,EAAE,EAAE;gBAC3B,SAAS,IAAI,CAAC,KAAK,EAAE;gBACrB,YAAY,IAAI,CAAC,OAAO,EAAE;gBAC1B,qBAAqB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;gBAC7C,iBAAiB;gBACjB,EAAE;gBACF,kFAAkF;gBAClF,sDAAsD,OAAO,CAAC,EAAE,uCAAuC;aACxG,CAAC;YAEF,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;aAC7D,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,OAAO;gBACL,OAAO,EAAE;oBACP,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,+BAA+B,OAAO,EAAE,EAAE;iBAC1E;gBACD,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC;CACF,CAAC"}
|