tru-mcp 0.5.2 → 0.7.0
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 +29 -40
- package/dist/api-client.d.ts +12 -1
- package/dist/api-client.js +16 -2
- package/dist/api-client.js.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/init.js +110 -9
- package/dist/init.js.map +1 -1
- package/dist/server.js +171 -138
- package/dist/server.js.map +1 -1
- package/dist/tools/add_agent_signup.d.ts +23 -0
- package/dist/tools/add_agent_signup.js +60 -0
- package/dist/tools/add_agent_signup.js.map +1 -0
- package/dist/tools/authenticate.js +1 -1
- package/dist/tools/authenticate.js.map +1 -1
- package/dist/tools/check_charge_status.js +1 -1
- package/dist/tools/check_charge_status.js.map +1 -1
- package/dist/tools/check_request_status.js +1 -1
- package/dist/tools/check_request_status.js.map +1 -1
- package/dist/tools/connect_stripe.js +10 -4
- package/dist/tools/connect_stripe.js.map +1 -1
- package/dist/tools/create_charge.d.ts +2 -0
- package/dist/tools/create_charge.js +76 -18
- package/dist/tools/create_charge.js.map +1 -1
- package/dist/tools/discover_api.js +16 -14
- package/dist/tools/discover_api.js.map +1 -1
- package/dist/tools/discover_apps.js +2 -2
- package/dist/tools/discover_apps.js.map +1 -1
- package/dist/tools/discover_products.d.ts +23 -0
- package/dist/tools/discover_products.js +55 -0
- package/dist/tools/discover_products.js.map +1 -0
- package/dist/tools/get_started.js +125 -54
- package/dist/tools/get_started.js.map +1 -1
- package/dist/tools/initiate_oauth.js +7 -3
- package/dist/tools/initiate_oauth.js.map +1 -1
- package/dist/tools/provision_user.js +1 -1
- package/dist/tools/provision_user.js.map +1 -1
- package/dist/tools/read_skill.js +2 -2
- package/dist/tools/read_skill.js.map +1 -1
- package/dist/tools/register_app.js +96 -10
- package/dist/tools/register_app.js.map +1 -1
- package/dist/tools/request_user_data.js +2 -2
- package/dist/tools/request_user_data.js.map +1 -1
- package/dist/tools/request_virtual_card.js +67 -7
- package/dist/tools/request_virtual_card.js.map +1 -1
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
-
import { checkIdentityTool } from "./tools/check_identity.js";
|
|
4
|
-
import { requestUserDataTool } from "./tools/request_user_data.js";
|
|
5
|
-
import { checkRequestStatusTool } from "./tools/check_request_status.js";
|
|
6
3
|
import { requestVirtualCardTool } from "./tools/request_virtual_card.js";
|
|
7
4
|
import { discoverAppsTool } from "./tools/discover_apps.js";
|
|
8
5
|
import { readSkillTool } from "./tools/read_skill.js";
|
|
@@ -15,6 +12,8 @@ import { getStartedTool } from "./tools/get_started.js";
|
|
|
15
12
|
import { discoverApiTool } from "./tools/discover_api.js";
|
|
16
13
|
import { provisionUserTool } from "./tools/provision_user.js";
|
|
17
14
|
import { authenticateTool } from "./tools/authenticate.js";
|
|
15
|
+
import { discoverProductsTool } from "./tools/discover_products.js";
|
|
16
|
+
import { addAgentSignupTool } from "./tools/add_agent_signup.js";
|
|
18
17
|
import { setClientName, getSourceLabel, saveSourceLabel, getSuggestedLabel, } from "./config.js";
|
|
19
18
|
// Re-export source label functions so existing tool imports work
|
|
20
19
|
export { getSourceLabel, saveSourceLabel, getSuggestedLabel };
|
|
@@ -24,9 +23,6 @@ const server = new McpServer({
|
|
|
24
23
|
});
|
|
25
24
|
// Register tools
|
|
26
25
|
server.tool(authenticateTool.name, authenticateTool.description, authenticateTool.inputSchema, authenticateTool.handler);
|
|
27
|
-
server.tool(checkIdentityTool.name, checkIdentityTool.description, checkIdentityTool.inputSchema, checkIdentityTool.handler);
|
|
28
|
-
server.tool(requestUserDataTool.name, requestUserDataTool.description, requestUserDataTool.inputSchema, requestUserDataTool.handler);
|
|
29
|
-
server.tool(checkRequestStatusTool.name, checkRequestStatusTool.description, checkRequestStatusTool.inputSchema, checkRequestStatusTool.handler);
|
|
30
26
|
server.tool(requestVirtualCardTool.name, requestVirtualCardTool.description, requestVirtualCardTool.inputSchema, requestVirtualCardTool.handler);
|
|
31
27
|
server.tool(discoverAppsTool.name, discoverAppsTool.description, discoverAppsTool.inputSchema, discoverAppsTool.handler);
|
|
32
28
|
server.tool(readSkillTool.name, readSkillTool.description, readSkillTool.inputSchema, readSkillTool.handler);
|
|
@@ -38,9 +34,11 @@ server.tool(connectStripeTool.name, connectStripeTool.description, connectStripe
|
|
|
38
34
|
server.tool(getStartedTool.name, getStartedTool.description, getStartedTool.inputSchema, getStartedTool.handler);
|
|
39
35
|
server.tool(discoverApiTool.name, discoverApiTool.description, discoverApiTool.inputSchema, discoverApiTool.handler);
|
|
40
36
|
server.tool(provisionUserTool.name, provisionUserTool.description, provisionUserTool.inputSchema, provisionUserTool.handler);
|
|
37
|
+
server.tool(discoverProductsTool.name, discoverProductsTool.description, discoverProductsTool.inputSchema, discoverProductsTool.handler);
|
|
38
|
+
server.tool(addAgentSignupTool.name, addAgentSignupTool.description, addAgentSignupTool.inputSchema, addAgentSignupTool.handler);
|
|
41
39
|
// ─── Prompts (show up as /tru:prompt-name in Claude Code) ──────
|
|
42
40
|
const BASE_URL = process.env.TRU_API_URL || "https://tru.so";
|
|
43
|
-
server.prompt("
|
|
41
|
+
server.prompt("dev-setup", "Full walkthrough for integrating tru into your app — auth, billing, identity verification, and agent discoverability", async () => {
|
|
44
42
|
let guide;
|
|
45
43
|
try {
|
|
46
44
|
const res = await fetch(`${BASE_URL}/agent.md`);
|
|
@@ -62,169 +60,204 @@ server.prompt("get-started", "Full walkthrough for integrating tru into your app
|
|
|
62
60
|
],
|
|
63
61
|
};
|
|
64
62
|
});
|
|
65
|
-
server.prompt("add-login", "Add OAuth login to your app — redirect-based
|
|
63
|
+
server.prompt("dev-add-login", "Add OAuth login to your app — redirect-based, branded to your app", async () => ({
|
|
66
64
|
messages: [
|
|
67
65
|
{
|
|
68
66
|
role: "user",
|
|
69
67
|
content: {
|
|
70
68
|
type: "text",
|
|
71
|
-
text: `You are adding OAuth login to this project. tru uses OAuth 2.0 with
|
|
72
|
-
|
|
73
|
-
**IMPORTANT: tru is invisible to the app's customers.** The login button should say "Login" or "Sign in" — NOT "Login with tru". The OAuth popup automatically inherits the app's brand color and looks like the app, not like tru. The only tru mention customers see is a small "secured by tru" in the popup footer.
|
|
74
|
-
|
|
75
|
-
## First: Decide the login strategy
|
|
76
|
-
|
|
77
|
-
Examine the app's existing auth setup and help the developer choose:
|
|
78
|
-
|
|
79
|
-
**Default recommendation: replace the existing login with tru.** tru auth uses Stripe Link — every user gets a verified identity and payment method in one step. Auth, billing, and identity become a single integration. Users without tru are auto-onboarded when they first pay (the billing popup handles Stripe Link payment + account creation seamlessly).
|
|
80
|
-
|
|
81
|
-
Only keep existing auth alongside tru if the app **requires social login providers** (Google, GitHub, etc.) or **enterprise SSO/SAML** that tru doesn't offer. In that case, add tru as an additional option and link accounts by email. Billing still works — those users get onboarded to tru at payment time via the guest payment flow.
|
|
82
|
-
|
|
83
|
-
## Steps
|
|
84
|
-
|
|
85
|
-
1. **Register the app on tru** (if not already done)
|
|
86
|
-
- Use the register_app tool or visit the tru dashboard
|
|
87
|
-
- Set redirect_uris to your OAuth callback URL (e.g. /api/auth/callback/tru)
|
|
88
|
-
- Set brand_color so the popup matches the app's look
|
|
89
|
-
|
|
90
|
-
2. **Add environment variables**
|
|
91
|
-
- TRU_API_URL — the tru instance URL
|
|
92
|
-
- TRU_CLIENT_ID — your app's ID from tru
|
|
93
|
-
- TRU_CLIENT_SECRET — your API key (same as TRU_API_KEY)
|
|
94
|
-
|
|
95
|
-
3. **Add a login button** that opens tru's authorize endpoint:
|
|
96
|
-
\`\`\`javascript
|
|
97
|
-
const url = new URL(\`\${TRU_URL}/api/oauth/authorize\`);
|
|
98
|
-
url.searchParams.set('client_id', TRU_CLIENT_ID);
|
|
99
|
-
url.searchParams.set('state', crypto.randomUUID());
|
|
100
|
-
window.open(url, 'tru-login', 'width=480,height=640');
|
|
101
|
-
\`\`\`
|
|
102
|
-
The button text should be "Login" or "Sign in" — no mention of tru.
|
|
103
|
-
Note: redirect_uri is NOT passed in the URL — it's configured in your app settings on tru.
|
|
104
|
-
|
|
105
|
-
4. **Add a callback route** (e.g. /api/auth/callback/tru):
|
|
106
|
-
- Receives ?code=AUTH_CODE&state=STATE
|
|
107
|
-
- Exchanges code for user info:
|
|
108
|
-
POST {TRU_URL}/api/oauth/token
|
|
109
|
-
Body: { "code": "...", "client_id": "...", "client_secret": "..." }
|
|
110
|
-
Response: { "user": { "id": "...", "email": "...", "name": "..." } }
|
|
111
|
-
- Creates/finds local user, sets session, closes popup
|
|
112
|
-
|
|
113
|
-
5. **Add an agent discovery link** below the login button:
|
|
114
|
-
\`\`\`html
|
|
115
|
-
<a href="/agent.md" style="font-size:11px;color:#999;text-decoration:none;">Agent guide</a>
|
|
116
|
-
\`\`\`
|
|
117
|
-
This helps AI agents browsing the page discover the app's skill file. Unobtrusive for humans.
|
|
118
|
-
|
|
119
|
-
6. **Account linking: match by email, not create.** When a user pays via the billing popup before ever logging in with tru, a tru account is auto-created with their email. If they later click "Login" (tru OAuth), your callback receives the same email. Your callback should find the existing account by email and link it — not create a duplicate.
|
|
120
|
-
\`\`\`javascript
|
|
121
|
-
// In your OAuth callback:
|
|
122
|
-
const truUser = await exchangeCode(code);
|
|
123
|
-
let user = await db.users.findByEmail(truUser.email);
|
|
124
|
-
if (!user) user = await db.users.create({ email: truUser.email, name: truUser.name });
|
|
125
|
-
await db.users.update(user.id, { tru_user_id: truUser.id });
|
|
126
|
-
setSession(user);
|
|
127
|
-
\`\`\`
|
|
128
|
-
|
|
129
|
-
7. **Add agent auth (403 response)** for bot detection:
|
|
130
|
-
Return a 403 with signup_url pointing to tru's authorize endpoint
|
|
131
|
-
|
|
132
|
-
Explore the codebase to understand the existing auth setup, then implement these steps.`,
|
|
133
|
-
},
|
|
134
|
-
},
|
|
135
|
-
],
|
|
136
|
-
}));
|
|
137
|
-
server.prompt("add-billing", "Add tru billing to your app — one-time charges and subscriptions via Stripe Connect", async () => ({
|
|
138
|
-
messages: [
|
|
139
|
-
{
|
|
140
|
-
role: "user",
|
|
141
|
-
content: {
|
|
142
|
-
type: "text",
|
|
143
|
-
text: `You are adding billing to this project. tru handles payments via Stripe Connect — money goes to the developer's Stripe account.
|
|
69
|
+
text: `You are adding OAuth login to this project. tru uses OAuth 2.0 with redirect-based auth.
|
|
144
70
|
|
|
145
|
-
**IMPORTANT: tru is invisible to the app's customers.**
|
|
71
|
+
**IMPORTANT: tru is invisible to the app's customers.** Buttons say "Login" or "Sign in" — NOT "Login with tru". The tru login screen inherits the app's brand_color and looks like the app. The only tru mention is a small "secured by tru" in the footer.
|
|
146
72
|
|
|
147
|
-
##
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
- Brand color should be set so billing popups match the app
|
|
151
|
-
|
|
152
|
-
## Creating charges
|
|
153
|
-
|
|
154
|
-
POST {TRU_URL}/api/billing/charges
|
|
155
|
-
Headers: X-API-Key: {api_key}, Content-Type: application/json
|
|
156
|
-
Body: {
|
|
157
|
-
"email": "user@example.com",
|
|
158
|
-
"amount_cents": 2999,
|
|
159
|
-
"description": "Pro Plan",
|
|
160
|
-
"type": "one_time"
|
|
161
|
-
}
|
|
73
|
+
## Strategy
|
|
74
|
+
|
|
75
|
+
**Default: replace existing login with tru.** tru uses Stripe Link — every user gets a verified identity and payment method in one step. Auth, billing, and identity become a single integration.
|
|
162
76
|
|
|
163
|
-
|
|
77
|
+
Only keep existing auth alongside tru if the app requires social providers (Google, GitHub) or enterprise SSO/SAML.
|
|
164
78
|
|
|
165
|
-
##
|
|
79
|
+
## Implementation
|
|
166
80
|
|
|
167
|
-
|
|
81
|
+
### 1. Environment variables
|
|
82
|
+
\`\`\`
|
|
83
|
+
TRU_API_URL=https://tru.so # or http://localhost:3001 for local dev
|
|
84
|
+
TRU_CLIENT_ID=<app-id> # from dev_register_app
|
|
85
|
+
TRU_CLIENT_SECRET=<api-key> # same as TRU_API_KEY
|
|
86
|
+
\`\`\`
|
|
87
|
+
|
|
88
|
+
### 2. Login button — open tru in a popup
|
|
168
89
|
\`\`\`javascript
|
|
169
|
-
|
|
90
|
+
function login() {
|
|
91
|
+
const state = crypto.randomUUID();
|
|
92
|
+
sessionStorage.setItem('oauth_state', state);
|
|
93
|
+
window.open(
|
|
94
|
+
\`\${TRU_URL}/api/oauth/authorize?client_id=\${CLIENT_ID}&state=\${state}\`,
|
|
95
|
+
'tru_login',
|
|
96
|
+
'width=480,height=700,left=200,top=100'
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Listen for login completion from popup
|
|
101
|
+
window.addEventListener('message', (e) => {
|
|
102
|
+
if (e.data?.type === 'tru_login_complete') {
|
|
103
|
+
window.location.href = '/'; // Reload to show dashboard
|
|
104
|
+
}
|
|
105
|
+
});
|
|
170
106
|
\`\`\`
|
|
171
|
-
|
|
107
|
+
Button text: "Login" or "Sign in" — no mention of tru.
|
|
172
108
|
|
|
173
|
-
|
|
109
|
+
The popup shows the Stripe Link account picker. User selects their account, popup closes, parent page reloads.
|
|
174
110
|
|
|
175
|
-
|
|
176
|
-
|
|
111
|
+
### 3. Server-side callback — set session, signal popup, close
|
|
112
|
+
\`\`\`javascript
|
|
113
|
+
app.get('/api/auth/callback/tru', async (req, res) => {
|
|
114
|
+
const { code } = req.query;
|
|
115
|
+
const response = await fetch(\`\${TRU_URL}/api/oauth/token\`, {
|
|
116
|
+
method: 'POST',
|
|
117
|
+
headers: { 'Content-Type': 'application/json' },
|
|
118
|
+
body: JSON.stringify({ code, client_id: CLIENT_ID, client_secret: CLIENT_SECRET }),
|
|
119
|
+
});
|
|
120
|
+
const { user } = await response.json();
|
|
121
|
+
|
|
122
|
+
// Match by email — don't create duplicates
|
|
123
|
+
let account = await db.users.findByEmail(user.email);
|
|
124
|
+
if (!account) account = await db.users.create({ email: user.email, name: user.name });
|
|
125
|
+
|
|
126
|
+
const sessionId = crypto.randomBytes(24).toString('hex');
|
|
127
|
+
sessions.set(sessionId, account.email);
|
|
128
|
+
res.setHeader('Set-Cookie', \`session=\${sessionId}; Path=/; HttpOnly; SameSite=Lax; Max-Age=86400\`);
|
|
129
|
+
|
|
130
|
+
// Signal parent window and close popup (fallback to redirect if not in popup)
|
|
131
|
+
res.send(\`<script>
|
|
132
|
+
if (window.opener) {
|
|
133
|
+
window.opener.postMessage({ type: 'tru_login_complete' }, '*');
|
|
134
|
+
window.close();
|
|
135
|
+
} else {
|
|
136
|
+
window.location.href = '/';
|
|
137
|
+
}
|
|
138
|
+
</script>\`);
|
|
139
|
+
});
|
|
140
|
+
\`\`\`
|
|
177
141
|
|
|
178
|
-
|
|
142
|
+
### 4. Post-login experience
|
|
143
|
+
The landing page shows Login for anonymous visitors. When the popup closes and the page reloads, check for session cookie on \`/\` and serve dashboard content instead of the landing page.
|
|
179
144
|
|
|
180
|
-
|
|
181
|
-
|
|
145
|
+
### 5. Account linking
|
|
146
|
+
When a user pays via billing before logging in, a tru account is auto-created with their email. If they later click Login, your callback gets the same email. Always find by email first — don't create duplicates.
|
|
182
147
|
|
|
183
|
-
|
|
148
|
+
### 6. Agent discovery link
|
|
149
|
+
Add a subtle link below the login button:
|
|
150
|
+
\`\`\`html
|
|
151
|
+
<a href="/agent.md" style="font-size:11px;color:#999;text-decoration:none;">Agent guide</a>
|
|
152
|
+
\`\`\`
|
|
153
|
+
|
|
154
|
+
Explore the codebase to understand the existing auth setup, then implement.`,
|
|
184
155
|
},
|
|
185
156
|
},
|
|
186
157
|
],
|
|
187
158
|
}));
|
|
188
|
-
server.prompt("
|
|
159
|
+
server.prompt("dev-add-billing", "Add tru billing to your app — one-time charges and subscriptions via Stripe Connect", async () => ({
|
|
189
160
|
messages: [
|
|
190
161
|
{
|
|
191
162
|
role: "user",
|
|
192
163
|
content: {
|
|
193
164
|
type: "text",
|
|
194
|
-
text: `You are adding
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
165
|
+
text: `You are adding billing to this project. tru handles payments via Stripe Connect — money goes to the developer's Stripe account.
|
|
166
|
+
|
|
167
|
+
**IMPORTANT: tru is invisible to the app's customers.** Buttons say "Subscribe", "Buy", or "Pay" — NOT "Subscribe with tru". The billing approval popup inherits the app's brand_color and looks like the app. The only tru mention is a small "secured by tru" in the popup footer.
|
|
168
|
+
|
|
169
|
+
## Prerequisites
|
|
170
|
+
- App registered on tru (dev_register_app tool)
|
|
171
|
+
- Stripe connected (dev_connect_stripe tool)
|
|
172
|
+
- brand_color set so billing popups match the app
|
|
173
|
+
|
|
174
|
+
## Server-side: Create charge and return approval URL
|
|
175
|
+
|
|
176
|
+
\`\`\`javascript
|
|
177
|
+
app.post('/api/purchase', auth, async (req, res) => {
|
|
178
|
+
const response = await fetch(\`\${TRU_URL}/api/billing/charges\`, {
|
|
179
|
+
method: 'POST',
|
|
180
|
+
headers: { 'X-API-Key': TRU_API_KEY, 'Content-Type': 'application/json' },
|
|
181
|
+
body: JSON.stringify({
|
|
182
|
+
email: req.user.email,
|
|
183
|
+
amount_cents: 499,
|
|
184
|
+
description: 'Pro subscription',
|
|
185
|
+
type: 'recurring', // or 'one_time'
|
|
186
|
+
interval: 'month', // for recurring: 'month' or 'year'
|
|
187
|
+
}),
|
|
188
|
+
});
|
|
189
|
+
const charge = await response.json();
|
|
190
|
+
|
|
191
|
+
// IMPORTANT: return approve_url so frontend can open the billing popup
|
|
192
|
+
res.json({
|
|
193
|
+
charge_id: charge.id,
|
|
194
|
+
status: charge.status,
|
|
195
|
+
approve_url: \`\${TRU_URL}/billing/approve/\${charge.id}\`,
|
|
196
|
+
poll_url: \`/api/purchase/status/\${charge.id}\`,
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// Poll endpoint for frontend to check charge status
|
|
201
|
+
app.get('/api/purchase/status/:chargeId', auth, async (req, res) => {
|
|
202
|
+
const response = await fetch(\`\${TRU_URL}/api/billing/charges/\${req.params.chargeId}\`, {
|
|
203
|
+
headers: { 'X-API-Key': TRU_API_KEY },
|
|
204
|
+
});
|
|
205
|
+
const data = await response.json();
|
|
206
|
+
if (data.status === 'completed' || data.status === 'approved') {
|
|
207
|
+
// Fulfill the purchase (add credits, activate subscription, etc.)
|
|
208
|
+
return res.json({ status: 'approved', ...fulfillmentData });
|
|
209
|
+
}
|
|
210
|
+
res.json({ status: data.status });
|
|
211
|
+
});
|
|
212
|
+
\`\`\`
|
|
213
|
+
|
|
214
|
+
## Client-side: Open approval popup and poll
|
|
215
|
+
|
|
216
|
+
\`\`\`javascript
|
|
217
|
+
async function purchase() {
|
|
218
|
+
const res = await fetch('/api/purchase', { method: 'POST', ... });
|
|
219
|
+
const data = await res.json();
|
|
220
|
+
|
|
221
|
+
// If auto-approved by user's spending rules, done immediately
|
|
222
|
+
if (data.status === 'completed' || data.status === 'approved') {
|
|
223
|
+
showSuccess();
|
|
224
|
+
return;
|
|
210
225
|
}
|
|
211
|
-
}
|
|
212
226
|
|
|
213
|
-
|
|
227
|
+
// Open tru billing approval in a popup
|
|
228
|
+
const popup = window.open(data.approve_url, 'tru_approve',
|
|
229
|
+
'width=480,height=700,left=200,top=100');
|
|
230
|
+
|
|
231
|
+
// Poll until approved or rejected, then close popup
|
|
232
|
+
const poll = setInterval(async () => {
|
|
233
|
+
const r = await fetch(data.poll_url);
|
|
234
|
+
const d = await r.json();
|
|
235
|
+
if (d.status === 'approved' || d.status === 'completed') {
|
|
236
|
+
clearInterval(poll);
|
|
237
|
+
if (popup && !popup.closed) popup.close();
|
|
238
|
+
showSuccess();
|
|
239
|
+
} else if (d.status === 'rejected') {
|
|
240
|
+
clearInterval(poll);
|
|
241
|
+
if (popup && !popup.closed) popup.close();
|
|
242
|
+
showError('Payment rejected');
|
|
243
|
+
}
|
|
244
|
+
}, 2000);
|
|
245
|
+
}
|
|
246
|
+
\`\`\`
|
|
214
247
|
|
|
215
|
-
|
|
216
|
-
Headers: X-API-Key: {api_key}
|
|
217
|
-
Body: { "email": "user@example.com", "fields": ["name", "email", "phone"] }
|
|
248
|
+
## Key patterns
|
|
218
249
|
|
|
219
|
-
|
|
250
|
+
1. **Billing uses popups, NOT redirects** (unlike login which uses redirects). The popup shows the tru billing approval page branded to the app.
|
|
251
|
+
2. **Always return approve_url** from the server so the frontend can open it.
|
|
252
|
+
3. **Poll for status** — don't rely on postMessage. Poll your own server endpoint every 2s.
|
|
253
|
+
4. **Handle auto-approve** — if the user has spending rules that allow the charge, it's approved instantly (no popup needed).
|
|
254
|
+
5. **Close popup on resolution** — when the poll detects approved/rejected, close the popup window.
|
|
255
|
+
6. **Both one-time and recurring** — same pattern for both. Set type to 'one_time' or 'recurring' with interval 'month'/'year'.
|
|
220
256
|
|
|
221
|
-
##
|
|
222
|
-
-
|
|
223
|
-
- Set trial length based on risk score
|
|
224
|
-
- Block duplicate signups via fingerprint_reuse
|
|
225
|
-
- Verify identity before high-value actions
|
|
257
|
+
## User experience
|
|
258
|
+
Users see a branded popup with the charge amount and description. They approve with their saved payment method or add a new one via Stripe Link. Users can set auto-approve rules in their wallet (e.g. "auto-approve charges under $10 from this app") — those charges skip the popup entirely.
|
|
226
259
|
|
|
227
|
-
Explore the codebase to find where
|
|
260
|
+
Explore the codebase to find where billing should be integrated, then implement.`,
|
|
228
261
|
},
|
|
229
262
|
},
|
|
230
263
|
],
|
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,
|
|
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,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EACL,aAAa,EACb,cAAc,EACd,eAAe,EACf,iBAAiB,GAClB,MAAM,aAAa,CAAC;AAErB,iEAAiE;AACjE,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,iBAAiB,EAAE,CAAC;AAE9D,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,cAAc;IACpB,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,iBAAiB;AACjB,MAAM,CAAC,IAAI,CACT,gBAAgB,CAAC,IAAI,EACrB,gBAAgB,CAAC,WAAW,EAC5B,gBAAgB,CAAC,WAAW,EAC5B,gBAAgB,CAAC,OAAO,CACzB,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,sBAAsB,CAAC,IAAI,EAC3B,sBAAsB,CAAC,WAAW,EAClC,sBAAsB,CAAC,WAAW,EAClC,sBAAsB,CAAC,OAAO,CAC/B,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,gBAAgB,CAAC,IAAI,EACrB,gBAAgB,CAAC,WAAW,EAC5B,gBAAgB,CAAC,WAAW,EAC5B,gBAAgB,CAAC,OAAO,CACzB,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,aAAa,CAAC,IAAI,EAClB,aAAa,CAAC,WAAW,EACzB,aAAa,CAAC,WAAW,EACzB,aAAa,CAAC,OAAO,CACtB,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,gBAAgB,CAAC,IAAI,EACrB,gBAAgB,CAAC,WAAW,EAC5B,gBAAgB,CAAC,WAAW,EAC5B,gBAAgB,CAAC,OAAO,CACzB,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,qBAAqB,CAAC,IAAI,EAC1B,qBAAqB,CAAC,WAAW,EACjC,qBAAqB,CAAC,WAAW,EACjC,qBAAqB,CAAC,OAAO,CAC9B,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,eAAe,CAAC,IAAI,EACpB,eAAe,CAAC,WAAW,EAC3B,eAAe,CAAC,WAAW,EAC3B,eAAe,CAAC,OAAO,CACxB,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,iBAAiB,CAAC,IAAI,EACtB,iBAAiB,CAAC,WAAW,EAC7B,iBAAiB,CAAC,WAAW,EAC7B,iBAAiB,CAAC,OAAO,CAC1B,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,iBAAiB,CAAC,IAAI,EACtB,iBAAiB,CAAC,WAAW,EAC7B,iBAAiB,CAAC,WAAW,EAC7B,iBAAiB,CAAC,OAAO,CAC1B,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,cAAc,CAAC,IAAI,EACnB,cAAc,CAAC,WAAW,EAC1B,cAAc,CAAC,WAAW,EAC1B,cAAc,CAAC,OAAO,CACvB,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,eAAe,CAAC,IAAI,EACpB,eAAe,CAAC,WAAW,EAC3B,eAAe,CAAC,WAAW,EAC3B,eAAe,CAAC,OAAO,CACxB,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,iBAAiB,CAAC,IAAI,EACtB,iBAAiB,CAAC,WAAW,EAC7B,iBAAiB,CAAC,WAAW,EAC7B,iBAAiB,CAAC,OAAO,CAC1B,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,oBAAoB,CAAC,IAAI,EACzB,oBAAoB,CAAC,WAAW,EAChC,oBAAoB,CAAC,WAAW,EAChC,oBAAoB,CAAC,OAAO,CAC7B,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,kBAAkB,CAAC,IAAI,EACvB,kBAAkB,CAAC,WAAW,EAC9B,kBAAkB,CAAC,WAAW,EAC9B,kBAAkB,CAAC,OAAO,CAC3B,CAAC;AAEF,kEAAkE;AAElE,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,gBAAgB,CAAC;AAE7D,MAAM,CAAC,MAAM,CACX,WAAW,EACX,sHAAsH,EACtH,KAAK,IAAI,EAAE;IACT,IAAI,KAAa,CAAC;IAClB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,QAAQ,WAAW,CAAC,CAAC;QAChD,KAAK,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,KAAK;YACH,yEAAyE,CAAC;IAC9E,CAAC;IACD,OAAO;QACL,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAe;gBACrB,OAAO,EAAE;oBACP,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,6IAA6I,KAAK,EAAE;iBAC3J;aACF;SACF;KACF,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,MAAM,CACX,eAAe,EACf,mEAAmE,EACnE,KAAK,IAAI,EAAE,CAAC,CAAC;IACX,QAAQ,EAAE;QACR;YACE,IAAI,EAAE,MAAe;YACrB,OAAO,EAAE;gBACP,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4EAqF4D;aACnE;SACF;KACF;CACF,CAAC,CACH,CAAC;AAEF,MAAM,CAAC,MAAM,CACX,iBAAiB,EACjB,qFAAqF,EACrF,KAAK,IAAI,EAAE,CAAC,CAAC;IACX,QAAQ,EAAE;QACR;YACE,IAAI,EAAE,MAAe;YACrB,OAAO,EAAE;gBACP,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iFA+FiE;aACxE;SACF;KACF;CACF,CAAC,CACH,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,GAAG;IACvB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,sEAAsE;IACtE,IAAI,CAAC;QACH,MAAM,IAAI,GAAI,MAAc,CAAC,MAAM,EAAE,gBAAgB,EAAE,EAAE,CAAC;QAC1D,IAAI,IAAI,EAAE,IAAI;YAAE,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IAEV,OAAO,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;AAC5D,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const addAgentSignupTool: {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
inputSchema: {
|
|
6
|
+
service_name: z.ZodOptional<z.ZodString>;
|
|
7
|
+
};
|
|
8
|
+
handler: (args: {
|
|
9
|
+
service_name?: string;
|
|
10
|
+
}) => Promise<{
|
|
11
|
+
content: {
|
|
12
|
+
type: "text";
|
|
13
|
+
text: string;
|
|
14
|
+
}[];
|
|
15
|
+
isError: boolean;
|
|
16
|
+
} | {
|
|
17
|
+
content: {
|
|
18
|
+
type: "text";
|
|
19
|
+
text: string;
|
|
20
|
+
}[];
|
|
21
|
+
isError?: undefined;
|
|
22
|
+
}>;
|
|
23
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { lookupAppByServiceName } from "../api-client.js";
|
|
3
|
+
import { getStoredApp } from "../config.js";
|
|
4
|
+
export const addAgentSignupTool = {
|
|
5
|
+
name: "dev_add_agent_signup",
|
|
6
|
+
description: "Returns the agent signup HTML snippet for the developer's app. The snippet is a single line that goes on the app's login page. " +
|
|
7
|
+
"Agents browsing the page will see it and follow it to the app's SKILL.md on tru.",
|
|
8
|
+
inputSchema: {
|
|
9
|
+
service_name: z
|
|
10
|
+
.string()
|
|
11
|
+
.optional()
|
|
12
|
+
.describe("The service_name of the app. If omitted, uses the app from ~/.tru/config.json (set by dev_register_app)."),
|
|
13
|
+
},
|
|
14
|
+
handler: async (args) => {
|
|
15
|
+
try {
|
|
16
|
+
const serviceName = args.service_name || getStoredApp()?.service_name;
|
|
17
|
+
if (!serviceName) {
|
|
18
|
+
return {
|
|
19
|
+
content: [{ type: "text", text: "No service_name provided and no app found in ~/.tru/config.json. Run dev_register_app first." }],
|
|
20
|
+
isError: true,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
// Verify the app exists
|
|
24
|
+
const lookup = await lookupAppByServiceName(serviceName);
|
|
25
|
+
if (lookup.status !== "registered" || !lookup.app) {
|
|
26
|
+
return {
|
|
27
|
+
content: [{ type: "text", text: `App "${serviceName}" not found on tru. Run dev_register_app first.` }],
|
|
28
|
+
isError: true,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
const snippet = `<a href="https://tru.so/apps/${serviceName}/SKILL.md" style="font-size:12px;color:#888;">AI Agent? Sign up with tru</a>`;
|
|
32
|
+
const guide = [
|
|
33
|
+
`## Agent Signup Snippet for ${lookup.app.display_name}`,
|
|
34
|
+
"",
|
|
35
|
+
"Add this one line to your login page:",
|
|
36
|
+
"",
|
|
37
|
+
"```html",
|
|
38
|
+
snippet,
|
|
39
|
+
"```",
|
|
40
|
+
"",
|
|
41
|
+
"**Where to place it:** After your login form or auth buttons. It should be subtle — small text below the main login UI.",
|
|
42
|
+
"",
|
|
43
|
+
"**What happens:** The link points to your app's SKILL.md on tru, which teaches agents how to authenticate and use your app. When an AI agent browses your login page, it sees this link and follows it to learn how to sign up via tru.",
|
|
44
|
+
"",
|
|
45
|
+
"**Next step:** Look for login pages in the codebase (e.g. login forms, auth pages, sign-in components) and add the snippet after the last login button.",
|
|
46
|
+
].join("\n");
|
|
47
|
+
return {
|
|
48
|
+
content: [{ type: "text", text: guide }],
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
53
|
+
return {
|
|
54
|
+
content: [{ type: "text", text: `Error: ${message}` }],
|
|
55
|
+
isError: true,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
//# sourceMappingURL=add_agent_signup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add_agent_signup.js","sourceRoot":"","sources":["../../src/tools/add_agent_signup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,IAAI,EAAE,sBAAsB;IAC5B,WAAW,EACT,iIAAiI;QACjI,kFAAkF;IACpF,WAAW,EAAE;QACX,YAAY,EAAE,CAAC;aACZ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,0GAA0G,CAAC;KACxH;IACD,OAAO,EAAE,KAAK,EAAE,IAA+B,EAAE,EAAE;QACjD,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,IAAI,YAAY,EAAE,EAAE,YAAY,CAAC;YACtE,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,OAAO;oBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,8FAA8F,EAAE,CAAC;oBAC1I,OAAO,EAAE,IAAI;iBACd,CAAC;YACJ,CAAC;YAED,wBAAwB;YACxB,MAAM,MAAM,GAAG,MAAM,sBAAsB,CAAC,WAAW,CAAC,CAAC;YACzD,IAAI,MAAM,CAAC,MAAM,KAAK,YAAY,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;gBAClD,OAAO;oBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,QAAQ,WAAW,iDAAiD,EAAE,CAAC;oBAChH,OAAO,EAAE,IAAI;iBACd,CAAC;YACJ,CAAC;YAED,MAAM,OAAO,GAAG,gCAAgC,WAAW,8EAA8E,CAAC;YAE1I,MAAM,KAAK,GAAG;gBACZ,+BAA+B,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE;gBACxD,EAAE;gBACF,uCAAuC;gBACvC,EAAE;gBACF,SAAS;gBACT,OAAO;gBACP,KAAK;gBACL,EAAE;gBACF,yHAAyH;gBACzH,EAAE;gBACF,yOAAyO;gBACzO,EAAE;gBACF,yJAAyJ;aAC1J,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAEb,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;aAClD,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,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,UAAU,OAAO,EAAE,EAAE,CAAC;gBAC/D,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC;CACF,CAAC"}
|
|
@@ -12,7 +12,7 @@ function openBrowser(url) {
|
|
|
12
12
|
exec(`${cmd} "${url}"`);
|
|
13
13
|
}
|
|
14
14
|
export const authenticateTool = {
|
|
15
|
-
name: "
|
|
15
|
+
name: "login",
|
|
16
16
|
description: "Authenticate with tru via the browser. " +
|
|
17
17
|
"Opens a browser window where you verify your identity, then waits until authentication is complete. " +
|
|
18
18
|
"Credentials are stored locally for future sessions.",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authenticate.js","sourceRoot":"","sources":["../../src/tools/authenticate.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEhF,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,SAAS,WAAW,CAAC,GAAW;IAC9B,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAClC,MAAM,GAAG,GACP,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAChC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YAChC,UAAU,CAAC;IACb,IAAI,CAAC,GAAG,GAAG,KAAK,GAAG,GAAG,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"authenticate.js","sourceRoot":"","sources":["../../src/tools/authenticate.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { getChargeStatus } from "../api-client.js";
|
|
3
3
|
export const checkChargeStatusTool = {
|
|
4
|
-
name: "
|
|
4
|
+
name: "check_payment_status",
|
|
5
5
|
description: "Check the status of a charge or subscription request. Returns pending, approved, rejected, or cancelled.",
|
|
6
6
|
inputSchema: {
|
|
7
7
|
charge_id: z
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check_charge_status.js","sourceRoot":"","sources":["../../src/tools/check_charge_status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"check_charge_status.js","sourceRoot":"","sources":["../../src/tools/check_charge_status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,IAAI,EAAE,sBAAsB;IAC5B,WAAW,EACT,0GAA0G;IAC5G,WAAW,EAAE;QACX,SAAS,EAAE,CAAC;aACT,MAAM,EAAE;aACR,QAAQ,CAAC,gCAAgC,CAAC;KAC9C;IACD,OAAO,EAAE,KAAK,EAAE,IAA2B,EAAE,EAAE;QAC7C,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAErD,MAAM,MAAM,GAAG,CAAC,MAAM,CAAC,YAAY,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YACtD,MAAM,QAAQ,GAAG,CAAC,MAAM,CAAC,QAAQ,IAAI,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;YAE1D,MAAM,KAAK,GAAG;gBACZ,WAAW,MAAM,CAAC,MAAM,EAAE;gBAC1B,YAAY,MAAM,IAAI,QAAQ,EAAE;gBAChC,SAAS,MAAM,CAAC,IAAI,EAAE;gBACtB,cAAc,MAAM,CAAC,EAAE,EAAE;aAC1B,CAAC;YAEF,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;gBACvB,KAAK,CAAC,IAAI,CAAC,gBAAgB,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;YACnD,CAAC;YACD,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;gBACtB,KAAK,CAAC,IAAI,CAAC,YAAY,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YAC9C,CAAC;YACD,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;gBACtB,KAAK,CAAC,IAAI,CAAC,YAAY,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YAC9C,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,KAAK,CAAC,EAAE,CAAC;gBAC5B,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE,wDAAwD;yBAC/D;qBACF;oBACD,OAAO,EAAE,IAAI;iBACd,CAAC;YACJ,CAAC;YAED,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,iCAAiC,OAAO,EAAE;qBACjD;iBACF;gBACD,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC;CACF,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { getRequestStatus } from "../api-client.js";
|
|
3
3
|
export const checkRequestStatusTool = {
|
|
4
|
-
name: "
|
|
4
|
+
name: "check_identity_status",
|
|
5
5
|
description: "Check the status of a credential sharing request. Returns 'pending', 'approved', or 'rejected'. If approved, returns the requested credential data.",
|
|
6
6
|
inputSchema: {
|
|
7
7
|
request_id: z.string().describe("The credential request ID to check"),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check_request_status.js","sourceRoot":"","sources":["../../src/tools/check_request_status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"check_request_status.js","sourceRoot":"","sources":["../../src/tools/check_request_status.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,7 +10,7 @@ function openBrowser(url) {
|
|
|
10
10
|
exec(`${cmd} "${url}"`);
|
|
11
11
|
}
|
|
12
12
|
export const connectStripeTool = {
|
|
13
|
-
name: "
|
|
13
|
+
name: "dev_connect_stripe",
|
|
14
14
|
description: "Connect a developer's Stripe account to their tru app. Works with the app's API key — no admin key needed. " +
|
|
15
15
|
"Opens a browser window for the developer to authorize via Stripe Connect OAuth. " +
|
|
16
16
|
"Once connected, charges approved by tru users are routed directly to the developer's Stripe account. " +
|
|
@@ -19,14 +19,14 @@ export const connectStripeTool = {
|
|
|
19
19
|
service_name: z
|
|
20
20
|
.string()
|
|
21
21
|
.optional()
|
|
22
|
-
.describe("The service_name of the app to connect. If omitted, uses the app from ~/.tru/config.json (set by
|
|
22
|
+
.describe("The service_name of the app to connect. If omitted, uses the app from ~/.tru/config.json (set by dev_register_app)."),
|
|
23
23
|
},
|
|
24
24
|
handler: async (args) => {
|
|
25
25
|
try {
|
|
26
26
|
const serviceName = args.service_name || getStoredApp()?.service_name;
|
|
27
27
|
if (!serviceName) {
|
|
28
28
|
return {
|
|
29
|
-
content: [{ type: "text", text: "No service_name provided and no app found in ~/.tru/config.json. Run
|
|
29
|
+
content: [{ type: "text", text: "No service_name provided and no app found in ~/.tru/config.json. Run dev_register_app first." }],
|
|
30
30
|
isError: true,
|
|
31
31
|
};
|
|
32
32
|
}
|
|
@@ -42,6 +42,9 @@ export const connectStripeTool = {
|
|
|
42
42
|
`- **Payouts enabled:** ${result.payouts_enabled ? "Yes" : "No"}`,
|
|
43
43
|
"",
|
|
44
44
|
"Charges approved by tru users will be routed to this Stripe account automatically.",
|
|
45
|
+
"",
|
|
46
|
+
"## Next step: Add login + provisioning",
|
|
47
|
+
"Continue to Step 4 of the dev_setup guide — add provisioning. Do NOT stop here.",
|
|
45
48
|
];
|
|
46
49
|
return {
|
|
47
50
|
content: [{ type: "text", text: lines.join("\n") }],
|
|
@@ -65,6 +68,9 @@ export const connectStripeTool = {
|
|
|
65
68
|
`- **Payouts enabled:** ${check.payouts_enabled ? "Yes" : "No"}`,
|
|
66
69
|
``,
|
|
67
70
|
`Charges approved by tru users will be routed to your Stripe account automatically.`,
|
|
71
|
+
``,
|
|
72
|
+
`## Next step: Add login + provisioning`,
|
|
73
|
+
`Continue to Step 4 of the dev_setup guide — add provisioning. Do NOT stop here.`,
|
|
68
74
|
];
|
|
69
75
|
return {
|
|
70
76
|
content: [{ type: "text", text: lines.join("\n") }],
|
|
@@ -79,7 +85,7 @@ export const connectStripeTool = {
|
|
|
79
85
|
return {
|
|
80
86
|
content: [{
|
|
81
87
|
type: "text",
|
|
82
|
-
text: `A browser window was opened to connect Stripe to ${result.display_name}, but authorization wasn't completed within 5 minutes.\n\nTo try again: ${result.url}\n\nOr run
|
|
88
|
+
text: `A browser window was opened to connect Stripe to ${result.display_name}, but authorization wasn't completed within 5 minutes.\n\nTo try again: ${result.url}\n\nOr run dev_connect_stripe again after completing the Stripe authorization.`,
|
|
83
89
|
}],
|
|
84
90
|
};
|
|
85
91
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connect_stripe.js","sourceRoot":"","sources":["../../src/tools/connect_stripe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,SAAS,WAAW,CAAC,GAAW;IAC9B,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAClC,MAAM,GAAG,GACP,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAChC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YAChC,UAAU,CAAC;IACb,IAAI,CAAC,GAAG,GAAG,KAAK,GAAG,GAAG,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"connect_stripe.js","sourceRoot":"","sources":["../../src/tools/connect_stripe.ts"],"names":[],"mappings":"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"}
|