@trusty-squire/mcp 0.1.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.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +83 -0
  3. package/dist/api-client.d.ts +130 -0
  4. package/dist/api-client.d.ts.map +1 -0
  5. package/dist/api-client.js +156 -0
  6. package/dist/api-client.js.map +1 -0
  7. package/dist/install/agents.d.ts +16 -0
  8. package/dist/install/agents.d.ts.map +1 -0
  9. package/dist/install/agents.js +171 -0
  10. package/dist/install/agents.js.map +1 -0
  11. package/dist/install/cli.d.ts +24 -0
  12. package/dist/install/cli.d.ts.map +1 -0
  13. package/dist/install/cli.js +277 -0
  14. package/dist/install/cli.js.map +1 -0
  15. package/dist/server.d.ts +4 -0
  16. package/dist/server.d.ts.map +1 -0
  17. package/dist/server.js +100 -0
  18. package/dist/server.js.map +1 -0
  19. package/dist/session.d.ts +25 -0
  20. package/dist/session.d.ts.map +1 -0
  21. package/dist/session.js +112 -0
  22. package/dist/session.js.map +1 -0
  23. package/dist/tools/cancel.d.ts +12 -0
  24. package/dist/tools/cancel.d.ts.map +1 -0
  25. package/dist/tools/cancel.js +34 -0
  26. package/dist/tools/cancel.js.map +1 -0
  27. package/dist/tools/get-credential.d.ts +15 -0
  28. package/dist/tools/get-credential.d.ts.map +1 -0
  29. package/dist/tools/get-credential.js +44 -0
  30. package/dist/tools/get-credential.js.map +1 -0
  31. package/dist/tools/get-usage.d.ts +6 -0
  32. package/dist/tools/get-usage.d.ts.map +1 -0
  33. package/dist/tools/get-usage.js +24 -0
  34. package/dist/tools/get-usage.js.map +1 -0
  35. package/dist/tools/index.d.ts +23 -0
  36. package/dist/tools/index.d.ts.map +1 -0
  37. package/dist/tools/index.js +48 -0
  38. package/dist/tools/index.js.map +1 -0
  39. package/dist/tools/list-services.d.ts +15 -0
  40. package/dist/tools/list-services.d.ts.map +1 -0
  41. package/dist/tools/list-services.js +55 -0
  42. package/dist/tools/list-services.js.map +1 -0
  43. package/dist/tools/list-subscriptions.d.ts +6 -0
  44. package/dist/tools/list-subscriptions.d.ts.map +1 -0
  45. package/dist/tools/list-subscriptions.js +25 -0
  46. package/dist/tools/list-subscriptions.js.map +1 -0
  47. package/dist/tools/provision-any.d.ts +120 -0
  48. package/dist/tools/provision-any.d.ts.map +1 -0
  49. package/dist/tools/provision-any.js +243 -0
  50. package/dist/tools/provision-any.js.map +1 -0
  51. package/dist/tools/provision.d.ts +30 -0
  52. package/dist/tools/provision.d.ts.map +1 -0
  53. package/dist/tools/provision.js +108 -0
  54. package/dist/tools/provision.js.map +1 -0
  55. package/dist/tools/rotate-credential.d.ts +12 -0
  56. package/dist/tools/rotate-credential.d.ts.map +1 -0
  57. package/dist/tools/rotate-credential.js +43 -0
  58. package/dist/tools/rotate-credential.js.map +1 -0
  59. package/dist/tools/wait-for-approval.d.ts +28 -0
  60. package/dist/tools/wait-for-approval.d.ts.map +1 -0
  61. package/dist/tools/wait-for-approval.js +82 -0
  62. package/dist/tools/wait-for-approval.js.map +1 -0
  63. package/package.json +43 -0
@@ -0,0 +1,243 @@
1
+ // provision_any — universal signup bot for any free API service.
2
+ //
3
+ // Runs the browser on the user's machine (their IP, their fingerprint).
4
+ // Aliases + inbox live on Trusty Squire's API so the SES forwarding
5
+ // pipeline (see apps/api/src/routes/ses-webhook.ts) can deliver
6
+ // verification emails.
7
+ //
8
+ // Auth model: Tier 0 machine token from the session file. No account or
9
+ // mandate required for free-tier signups. When the user hits their quota
10
+ // the API returns a structured quota_exceeded response and we tell Claude
11
+ // to surface a pairing CTA.
12
+ import { z } from "zod";
13
+ import { UniversalSignupBot, InboxClient, ProxyLLMClient, detectAsn, } from "@trusty-squire/universal-bot";
14
+ import { openSessionStorage } from "../session.js";
15
+ export const provisionAnyInputSchema = z.object({
16
+ service: z.string().describe("Name of the service to sign up for (e.g., 'Postmark', 'Mailgun')"),
17
+ signup_url: z.string().optional().describe("Direct URL to signup page (optional, will search if not provided)"),
18
+ });
19
+ // JSON Schema for MCP `tools/list`. The SDK forwards `inputSchema` verbatim
20
+ // to the host agent (Claude Code, Goose, etc.); a zod object stringifies to
21
+ // `{}` and leaves the LLM blind to required parameters. The schema here
22
+ // must mirror `provisionAnyInputSchema` above.
23
+ const PROVISION_ANY_JSON_SCHEMA = {
24
+ type: "object",
25
+ required: ["service"],
26
+ properties: {
27
+ service: {
28
+ type: "string",
29
+ description: "Name of the service to sign up for (e.g., 'Postmark', 'Mailgun', 'IPInfo')",
30
+ },
31
+ signup_url: {
32
+ type: "string",
33
+ description: "Direct URL to the service's signup page. Optional — the bot will navigate from the service name if omitted.",
34
+ },
35
+ },
36
+ };
37
+ const DESCRIPTION = `Sign up for any free API service automatically using browser automation.
38
+
39
+ WHEN TO CALL THIS TOOL:
40
+ - The user wants an account for a service Trusty Squire doesn't have a native adapter for
41
+ - Call list_services first; if the service ISN'T in the directory, use this tool
42
+ - Best for free-tier developer services with traditional email/password signup
43
+
44
+ BEHAVIOR:
45
+ - Runs Playwright on the user's machine (uses their IP for captcha resilience)
46
+ - Receives verification emails via Trusty Squire's SES inbound infrastructure
47
+ - Returns API credentials directly on success
48
+ - Free for the first N signups per machine (Tier 0); after that, returns a
49
+ pairing CTA the user clicks to upgrade
50
+
51
+ POSSIBLE RESPONSES:
52
+ - status="success" + credentials → use them immediately
53
+ - status="quota_exceeded" + cta_pair_url → tell the user to run \`npx @trusty-squire/mcp pair\`
54
+ or open the URL to upgrade. Their next signup will work.
55
+ - status="captcha_blocked" → the signup site uses captcha we can't bypass. Tell the user
56
+ to sign up manually at the service's signup URL.
57
+ - status="failed" → the form filled but submission didn't yield credentials. Show steps[].`;
58
+ export const provisionAnyTool = {
59
+ name: "provision_any_service",
60
+ description: DESCRIPTION,
61
+ jsonInputSchema: PROVISION_ANY_JSON_SCHEMA,
62
+ inputSchema: provisionAnyInputSchema,
63
+ handler: async (input, _api) => {
64
+ // Pull the machine token from session storage. The install CLI writes it.
65
+ const storage = await openSessionStorage();
66
+ const session = await storage.read();
67
+ if (session === null || session.machine_token === undefined) {
68
+ // Production users hit this when they've never run the install CLI.
69
+ // Local-dev users hit this if their session.json only has an
70
+ // agent_session_token (Tier 1 pair without a machine_token issued).
71
+ // Surface both paths so the agent can route the user correctly.
72
+ const hasPartialSession = session !== null && session.agent_session_token !== undefined;
73
+ return {
74
+ status: "not_installed",
75
+ message: hasPartialSession
76
+ ? "This machine is paired (Tier 1) but has no Tier 0 machine_token, which provision_any_service requires. Run `node /home/chode/trusty-squire/apps/mcp/dist/install/cli.js install --target=goose` to issue one, or in production run `npx @trusty-squire/mcp install`."
77
+ : "Trusty Squire isn't installed on this machine. In production run `npx @trusty-squire/mcp install`. For local dev against this repo run `node /home/chode/trusty-squire/apps/mcp/dist/install/cli.js install --target=goose`.",
78
+ };
79
+ }
80
+ const apiBase = session.api_base_url;
81
+ // Create an alias through the API (consumes one quota slot for Tier 0).
82
+ const inboxClient = new InboxClient({
83
+ baseUrl: apiBase,
84
+ apiKey: session.machine_token,
85
+ });
86
+ const runId = `mcp-${Date.now().toString(36)}`;
87
+ let alias;
88
+ try {
89
+ alias = await inboxClient.createAlias({
90
+ account_id: session.account_id ?? "anonymous",
91
+ service: input.service,
92
+ run_id: runId,
93
+ });
94
+ // eslint-disable-next-line no-console
95
+ console.error(`[provision-any] alias=${alias} apiBase=${apiBase}`);
96
+ }
97
+ catch (err) {
98
+ const message = err instanceof Error ? err.message : String(err);
99
+ // The createAlias error body has the structured payload; parse it back.
100
+ if (/quota_exceeded/.test(message)) {
101
+ const match = message.match(/\{.*\}/s);
102
+ if (match !== null) {
103
+ try {
104
+ const parsed = JSON.parse(match[0]);
105
+ return {
106
+ status: "quota_exceeded",
107
+ service: input.service,
108
+ quota_limit: parsed["quota_limit"],
109
+ quota_used: parsed["quota_used"],
110
+ cta_pair_url: parsed["cta_pair_url"],
111
+ message: "You've used your free signups on this machine. " +
112
+ "Run `npx @trusty-squire/mcp pair` (or open the cta_pair_url) to upgrade.",
113
+ };
114
+ }
115
+ catch {
116
+ // fall through
117
+ }
118
+ }
119
+ }
120
+ return {
121
+ status: "error",
122
+ service: input.service,
123
+ error: message,
124
+ message: `Couldn't reach Trusty Squire's API to set up an alias.`,
125
+ };
126
+ }
127
+ // Construct an LLMPair that routes through Trusty Squire's proxy.
128
+ // The user pays nothing for LLM calls — the operator's OpenRouter
129
+ // key handles them server-side, gated by the machine token's
130
+ // rolling rate limit. Cheap mode (Gemini Flash) is the primary;
131
+ // Sonnet is the parse-failure fallback.
132
+ const llmPair = {
133
+ primary: new ProxyLLMClient({
134
+ apiBaseUrl: apiBase,
135
+ machineToken: session.machine_token,
136
+ tier: "cheap",
137
+ }),
138
+ premium: new ProxyLLMClient({
139
+ apiBaseUrl: apiBase,
140
+ machineToken: session.machine_token,
141
+ tier: "premium",
142
+ }),
143
+ };
144
+ // Run the bot locally with this alias. Bot uses the inboxClient to long-
145
+ // poll the API for any verification emails that arrive via SES.
146
+ const bot = new UniversalSignupBot();
147
+ const result = await bot.signup({
148
+ service: input.service,
149
+ ...(input.signup_url !== undefined ? { signupUrl: input.signup_url } : {}),
150
+ email: alias,
151
+ inbox: inboxClient,
152
+ llm: llmPair,
153
+ });
154
+ // Best-effort cleanup of the alias once we're done with it. Failure is
155
+ // non-fatal — the alias TTL-expires anyway.
156
+ try {
157
+ await inboxClient.revokeAlias(alias);
158
+ }
159
+ catch {
160
+ // noop
161
+ }
162
+ // If a captcha was encountered (whether or not we got past it),
163
+ // report it to the API for the analytics ledger. The result.captcha
164
+ // field is set by the agent's pre/post-submit/re-plan gates. We do
165
+ // a fresh asn lookup at event time rather than relying on the
166
+ // install-time one — users move networks, and "where was the
167
+ // machine when this happened" is the analytically interesting bit.
168
+ if (result.captcha !== undefined) {
169
+ // Fire-and-forget; we don't want the captcha-event POST to
170
+ // affect what the user sees. Failures here are logged to stderr
171
+ // and otherwise ignored.
172
+ void postCaptchaEvent(apiBase, session.machine_token, {
173
+ service: input.service,
174
+ captcha_kind: result.captcha.kind,
175
+ blocked: result.captcha.blocked,
176
+ });
177
+ }
178
+ if (result.success && result.credentials !== undefined) {
179
+ return {
180
+ status: "success",
181
+ service: input.service,
182
+ credentials: result.credentials,
183
+ steps: result.steps,
184
+ message: `Successfully signed up for ${input.service}. Credentials are in this response — show them to the user (or save to their .env).`,
185
+ };
186
+ }
187
+ // Authoritative: if the agent recorded a captcha encounter and
188
+ // marked it blocked, that's a captcha_blocked outcome. Replaces
189
+ // the earlier substring heuristic which had to scan steps[].
190
+ if (result.captcha !== undefined && result.captcha.blocked) {
191
+ return {
192
+ status: "captcha_blocked",
193
+ service: input.service,
194
+ error: result.error ?? "Captcha challenge blocked automated signup.",
195
+ steps: result.steps,
196
+ captcha_kind: result.captcha.kind,
197
+ browser_channel: result.browser_channel ?? null,
198
+ message: `${input.service} blocked automated signup with a ${result.captcha.kind} captcha. ` +
199
+ `Tell the user to sign up manually at ${input.signup_url ?? `https://${input.service.toLowerCase()}.com`}.`,
200
+ };
201
+ }
202
+ return {
203
+ status: "failed",
204
+ service: input.service,
205
+ error: result.error ?? "Unknown error",
206
+ steps: result.steps,
207
+ browser_channel: result.browser_channel ?? null,
208
+ message: `Couldn't finish signing up for ${input.service}. Show the user the steps[] for debugging.`,
209
+ };
210
+ },
211
+ };
212
+ // Best-effort POST to /v1/captcha-events. We don't care about the
213
+ // response — at worst the event is lost, which is no worse than the
214
+ // pre-instrumentation state. Captures fresh asn at event time when
215
+ // possible; the API also falls back to the install-time asn from the
216
+ // MachineToken row if we can't supply one here.
217
+ async function postCaptchaEvent(apiBase, machineToken, event) {
218
+ try {
219
+ const asn = await detectAsn();
220
+ const body = {
221
+ service: event.service,
222
+ captcha_kind: event.captcha_kind,
223
+ blocked: event.blocked,
224
+ ...(asn !== null
225
+ ? {
226
+ asn: { class: asn.class, org: asn.org, country: asn.country, number: asn.asn },
227
+ }
228
+ : {}),
229
+ };
230
+ await fetch(`${apiBase}/v1/captcha-events`, {
231
+ method: "POST",
232
+ headers: {
233
+ "content-type": "application/json",
234
+ "x-machine-token": machineToken,
235
+ },
236
+ body: JSON.stringify(body),
237
+ });
238
+ }
239
+ catch (err) {
240
+ console.error(`[provision-any] captcha event report failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`);
241
+ }
242
+ }
243
+ //# sourceMappingURL=provision-any.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provision-any.js","sourceRoot":"","sources":["../../src/tools/provision-any.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { z } from "zod";
2
+ import { type Tool } from "./index.js";
3
+ declare const inputSchema: z.ZodObject<{
4
+ service: z.ZodString;
5
+ plan: z.ZodDefault<z.ZodString>;
6
+ project_name: z.ZodString;
7
+ category: z.ZodOptional<z.ZodString>;
8
+ cost_cents: z.ZodDefault<z.ZodNumber>;
9
+ recurrence: z.ZodDefault<z.ZodEnum<["one_time", "monthly", "yearly", "none"]>>;
10
+ requirements: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
11
+ }, "strip", z.ZodTypeAny, {
12
+ service: string;
13
+ plan: string;
14
+ project_name: string;
15
+ cost_cents: number;
16
+ recurrence: "one_time" | "monthly" | "yearly" | "none";
17
+ category?: string | undefined;
18
+ requirements?: Record<string, unknown> | undefined;
19
+ }, {
20
+ service: string;
21
+ project_name: string;
22
+ plan?: string | undefined;
23
+ category?: string | undefined;
24
+ cost_cents?: number | undefined;
25
+ recurrence?: "one_time" | "monthly" | "yearly" | "none" | undefined;
26
+ requirements?: Record<string, unknown> | undefined;
27
+ }>;
28
+ export declare const provisionTool: Tool<z.infer<typeof inputSchema>>;
29
+ export {};
30
+ //# sourceMappingURL=provision.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provision.d.ts","sourceRoot":"","sources":["../../src/tools/provision.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAgB,KAAK,IAAI,EAAE,MAAM,YAAY,CAAC;AAErD,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;EAaf,CAAC;AA8BH,eAAO,MAAM,aAAa,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAiE3D,CAAC"}
@@ -0,0 +1,108 @@
1
+ import { z } from "zod";
2
+ import { assertPaired } from "./index.js";
3
+ const inputSchema = z.object({
4
+ service: z.string().min(1),
5
+ plan: z.string().min(1).default("free"),
6
+ project_name: z.string().min(1).max(120),
7
+ // The runtime needs category + cost for the mandate evaluator;
8
+ // the MCP tool's caller may not know these. When omitted, we
9
+ // request the registry directory for default category.
10
+ category: z.string().optional(),
11
+ cost_cents: z.number().int().nonnegative().default(0),
12
+ recurrence: z
13
+ .enum(["one_time", "monthly", "yearly", "none"])
14
+ .default("none"),
15
+ requirements: z.record(z.string(), z.unknown()).optional(),
16
+ });
17
+ const DESCRIPTION = `Sign up for and configure a SaaS service on the user's behalf, returning
18
+ working credentials. The user has pre-authorized spending within their
19
+ spending policy, so no manual signup, email verification, or card entry
20
+ is needed from them.
21
+
22
+ WHEN TO CALL THIS TOOL:
23
+ - The user's project needs an API key for any external SaaS
24
+ - You would otherwise instruct the user to "go sign up at example.com"
25
+ - You need a service-specific credential the user does not yet have
26
+ - The user mentions needing hosting, a database, email, monitoring,
27
+ auth, AI APIs, payments, analytics, error tracking, or similar
28
+
29
+ DO NOT instruct the user to sign up manually if a Squire adapter exists.
30
+ Call list_services first if you are unsure whether the service is supported.
31
+
32
+ BEHAVIOR:
33
+ - Free tiers are auto-approved within the user's spending policy (silent)
34
+ - Paid tiers above the silent ceiling return status="pending_approval"
35
+ with a one-click approval link the user can click in their terminal
36
+ - Returns within 3-15 seconds for native adapters, up to 60s for browser-based
37
+ - Stores credentials in the user's vault automatically
38
+ - Idempotent on (user, service, project_name)
39
+
40
+ AFTER PROVISIONING:
41
+ - Use get_credential() to retrieve the API key for use in code
42
+ - Reference credentials via env vars; do not paste secrets into source files
43
+ - Tell the user what was set up and the cost, even when silent`;
44
+ export const provisionTool = {
45
+ name: "provision",
46
+ description: DESCRIPTION,
47
+ inputSchema,
48
+ jsonInputSchema: {
49
+ type: "object",
50
+ required: ["service", "project_name"],
51
+ properties: {
52
+ service: { type: "string" },
53
+ plan: { type: "string", default: "free" },
54
+ project_name: { type: "string" },
55
+ category: { type: "string" },
56
+ cost_cents: { type: "integer", minimum: 0, default: 0 },
57
+ recurrence: {
58
+ type: "string",
59
+ enum: ["one_time", "monthly", "yearly", "none"],
60
+ default: "none",
61
+ },
62
+ requirements: { type: "object" },
63
+ },
64
+ },
65
+ async handler(args, api) {
66
+ assertPaired(api);
67
+ // If the caller didn't supply category, look it up in the registry.
68
+ let category = args.category;
69
+ if (category === undefined) {
70
+ const dir = await api.listServices();
71
+ const match = dir.adapters.find((a) => a.service === args.service);
72
+ category = match?.category ?? "unknown";
73
+ }
74
+ const res = await api.createRun({
75
+ service: args.service,
76
+ plan: args.plan,
77
+ project_name: args.project_name,
78
+ category,
79
+ cost_cents: args.cost_cents,
80
+ recurrence: args.recurrence,
81
+ });
82
+ if (res.decision === "silent") {
83
+ return {
84
+ status: "active",
85
+ run_id: res.run.id,
86
+ run_state: res.run.state,
87
+ message: "Sign-up enqueued silently within the user's spending policy.",
88
+ };
89
+ }
90
+ if (res.decision === "needs_approval") {
91
+ return {
92
+ status: "pending_approval",
93
+ run_id: res.run.id,
94
+ run_state: res.run.state,
95
+ approval_url: res.approval_url,
96
+ reasons: res.reasons ?? [],
97
+ required_confidence: res.required_confidence ?? "high",
98
+ message: "Approval required. Show the user the approval_url so they can confirm.",
99
+ };
100
+ }
101
+ return {
102
+ status: "rejected",
103
+ run_id: res.run.id,
104
+ message: "The mandate rejected this action.",
105
+ };
106
+ },
107
+ };
108
+ //# sourceMappingURL=provision.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provision.js","sourceRoot":"","sources":["../../src/tools/provision.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { z } from "zod";
2
+ import type { Tool } from "./index.js";
3
+ declare const inputSchema: z.ZodObject<{
4
+ reference: z.ZodString;
5
+ }, "strip", z.ZodTypeAny, {
6
+ reference: string;
7
+ }, {
8
+ reference: string;
9
+ }>;
10
+ export declare const rotateCredentialTool: Tool<z.infer<typeof inputSchema>>;
11
+ export {};
12
+ //# sourceMappingURL=rotate-credential.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rotate-credential.d.ts","sourceRoot":"","sources":["../../src/tools/rotate-credential.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,QAAA,MAAM,WAAW;;;;;;EAEf,CAAC;AAoBH,eAAO,MAAM,oBAAoB,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAqBlE,CAAC"}
@@ -0,0 +1,43 @@
1
+ import { z } from "zod";
2
+ const inputSchema = z.object({
3
+ reference: z.string().min(1),
4
+ });
5
+ const DESCRIPTION = `Rotate a vault-stored credential (e.g. when the user suspects a leak).
6
+ The adapter's rotate flow generates a fresh credential, stores it in
7
+ the vault under the same reference, and revokes the old value at the
8
+ service.
9
+
10
+ WHEN TO CALL THIS TOOL:
11
+ - The user explicitly asks "rotate the X key"
12
+ - A credential leak has been confirmed
13
+ - Compliance policy requires periodic rotation and the rotation due
14
+ date has passed
15
+
16
+ BEHAVIOR:
17
+ - Default confidence requirement is medium (not high) — rotation is a
18
+ privileged operation but doesn't authorize new spending
19
+ - In v0 the rotate flow is partially wired; the rotate adapter step
20
+ exists but the runtime's flow selector doesn't pick the rotate flow
21
+ yet — see chunk 11+ roadmap. This tool currently returns 202.`;
22
+ export const rotateCredentialTool = {
23
+ name: "rotate_credential",
24
+ description: DESCRIPTION,
25
+ inputSchema,
26
+ jsonInputSchema: {
27
+ type: "object",
28
+ required: ["reference"],
29
+ properties: { reference: { type: "string" } },
30
+ },
31
+ async handler(args, _api) {
32
+ // v0 stub. The endpoint doesn't exist on apps/api yet — the chunk-11
33
+ // spec lists rotate as a future improvement. We return a clear
34
+ // not-implemented body so the coding agent can surface this to
35
+ // the user rather than acting on a false success.
36
+ return {
37
+ status: "not_implemented",
38
+ reference: args.reference,
39
+ message: "Credential rotation is a v0 stub. The cancel + rotate flow selectors arrive in a later chunk. Track progress at /v1/usage.",
40
+ };
41
+ },
42
+ };
43
+ //# sourceMappingURL=rotate-credential.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rotate-credential.js","sourceRoot":"","sources":["../../src/tools/rotate-credential.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CAC7B,CAAC,CAAC;AAEH,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;gEAgB4C,CAAC;AAEjE,MAAM,CAAC,MAAM,oBAAoB,GAAsC;IACrE,IAAI,EAAE,mBAAmB;IACzB,WAAW,EAAE,WAAW;IACxB,WAAW;IACX,eAAe,EAAE;QACf,IAAI,EAAE,QAAQ;QACd,QAAQ,EAAE,CAAC,WAAW,CAAC;QACvB,UAAU,EAAE,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;KAC9C;IACD,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI;QACtB,qEAAqE;QACrE,+DAA+D;QAC/D,+DAA+D;QAC/D,kDAAkD;QAClD,OAAO;YACL,MAAM,EAAE,iBAAiB;YACzB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,OAAO,EACL,4HAA4H;SAC/H,CAAC;IACJ,CAAC;CACF,CAAC"}
@@ -0,0 +1,28 @@
1
+ import { z } from "zod";
2
+ import type { ApiClient } from "../api-client.js";
3
+ import { type Tool } from "./index.js";
4
+ declare const inputSchema: z.ZodObject<{
5
+ run_id: z.ZodString;
6
+ timeout_seconds: z.ZodDefault<z.ZodNumber>;
7
+ poll_interval_seconds: z.ZodDefault<z.ZodNumber>;
8
+ }, "strip", z.ZodTypeAny, {
9
+ run_id: string;
10
+ timeout_seconds: number;
11
+ poll_interval_seconds: number;
12
+ }, {
13
+ run_id: string;
14
+ timeout_seconds?: number | undefined;
15
+ poll_interval_seconds?: number | undefined;
16
+ }>;
17
+ export declare const waitForApprovalTool: Tool<z.infer<typeof inputSchema>>;
18
+ export declare function waitForApprovalImpl(args: z.infer<typeof inputSchema>, api: ApiClient, options?: {
19
+ sleep?: (ms: number) => Promise<void>;
20
+ now?: () => number;
21
+ }): Promise<{
22
+ status: string;
23
+ run_state: string;
24
+ run_id: string;
25
+ reason?: string;
26
+ }>;
27
+ export {};
28
+ //# sourceMappingURL=wait-for-approval.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wait-for-approval.d.ts","sourceRoot":"","sources":["../../src/tools/wait-for-approval.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAgB,KAAK,IAAI,EAAE,MAAM,YAAY,CAAC;AAErD,QAAA,MAAM,WAAW;;;;;;;;;;;;EAIf,CAAC;AAcH,eAAO,MAAM,mBAAmB,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAiBjE,CAAC;AAEF,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,EACjC,GAAG,EAAE,SAAS,EACd,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CAAO,GAC1E,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAyBjF"}
@@ -0,0 +1,82 @@
1
+ import { z } from "zod";
2
+ import { assertPaired } from "./index.js";
3
+ const inputSchema = z.object({
4
+ run_id: z.string().min(1),
5
+ timeout_seconds: z.number().int().positive().max(600).default(120),
6
+ poll_interval_seconds: z.number().int().positive().max(30).default(2),
7
+ });
8
+ const DESCRIPTION = `Wait for a run that's in pending_approval to be granted or denied by the user.
9
+ Returns the final status once the run leaves PENDING_APPROVAL or the timeout elapses.
10
+
11
+ WHEN TO CALL THIS TOOL:
12
+ - After provision() returns status="pending_approval"
13
+ - When you want to block until the user clicks the approval link
14
+
15
+ BEHAVIOR:
16
+ - Polls the run every poll_interval_seconds (default 2s)
17
+ - Returns once the run leaves PENDING_APPROVAL or timeout_seconds elapses
18
+ - Does NOT auto-grant; only the user can grant via the approval URL`;
19
+ export const waitForApprovalTool = {
20
+ name: "wait_for_approval",
21
+ description: DESCRIPTION,
22
+ inputSchema,
23
+ jsonInputSchema: {
24
+ type: "object",
25
+ required: ["run_id"],
26
+ properties: {
27
+ run_id: { type: "string" },
28
+ timeout_seconds: { type: "integer", minimum: 1, maximum: 600, default: 120 },
29
+ poll_interval_seconds: { type: "integer", minimum: 1, maximum: 30, default: 2 },
30
+ },
31
+ },
32
+ async handler(args, api) {
33
+ assertPaired(api);
34
+ return waitForApprovalImpl(args, api);
35
+ },
36
+ };
37
+ export async function waitForApprovalImpl(args, api, options = {}) {
38
+ const sleep = options.sleep ?? defaultSleep;
39
+ const now = options.now ?? (() => Date.now());
40
+ const deadline = now() + args.timeout_seconds * 1000;
41
+ while (true) {
42
+ const run = await api.getRun(args.run_id);
43
+ if (run.state !== "PENDING_APPROVAL") {
44
+ return {
45
+ status: terminalDescription(run.state),
46
+ run_state: run.state,
47
+ run_id: run.id,
48
+ ...(run.failure_reason !== null ? { reason: run.failure_reason } : {}),
49
+ };
50
+ }
51
+ if (now() >= deadline) {
52
+ return {
53
+ status: "timeout",
54
+ run_state: run.state,
55
+ run_id: run.id,
56
+ reason: "wait_for_approval_timed_out",
57
+ };
58
+ }
59
+ await sleep(args.poll_interval_seconds * 1000);
60
+ }
61
+ }
62
+ function defaultSleep(ms) {
63
+ return new Promise((resolve) => setTimeout(resolve, ms));
64
+ }
65
+ function terminalDescription(state) {
66
+ switch (state) {
67
+ case "PROVISIONING":
68
+ case "ADAPTER_EXECUTING":
69
+ case "CRED_EXTRACTED":
70
+ case "VAULT_WRITTEN":
71
+ return "granted";
72
+ case "COMPLETE":
73
+ return "active";
74
+ case "REJECTED":
75
+ return "denied";
76
+ case "FAILED":
77
+ return "failed";
78
+ default:
79
+ return state.toLowerCase();
80
+ }
81
+ }
82
+ //# sourceMappingURL=wait-for-approval.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wait-for-approval.js","sourceRoot":"","sources":["../../src/tools/wait-for-approval.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@trusty-squire/mcp",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "Local MCP server vibe coding agents install. Thin relay to the Trusty Squire API.",
6
+ "main": "./dist/server.js",
7
+ "bin": {
8
+ "squire-mcp": "./dist/install/cli.js"
9
+ },
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+ "engines": {
17
+ "node": ">=20"
18
+ },
19
+ "dependencies": {
20
+ "@modelcontextprotocol/sdk": "^1.0.4",
21
+ "open": "^10.1.0",
22
+ "yaml": "^2.6.1",
23
+ "zod": "^3.23.8",
24
+ "@trusty-squire/universal-bot": "0.1.0"
25
+ },
26
+ "optionalDependencies": {
27
+ "keytar": "^7.9.0"
28
+ },
29
+ "devDependencies": {
30
+ "@vitest/coverage-v8": "^1.6.1",
31
+ "tsx": "^4.7.0",
32
+ "typescript": "^5.3.3",
33
+ "vitest": "^1.2.0"
34
+ },
35
+ "scripts": {
36
+ "build": "tsc -p tsconfig.build.json",
37
+ "typecheck": "tsc --noEmit -p tsconfig.json",
38
+ "test": "vitest run",
39
+ "test:cov": "vitest run --coverage",
40
+ "dev:server": "tsx src/server.ts",
41
+ "install:dev": "tsx src/install/cli.ts"
42
+ }
43
+ }