premanmcp 0.3.4
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/LICENSE +21 -0
- package/README.md +137 -0
- package/bin/cli.js +168 -0
- package/dist/auth_flow_ui.d.ts +35 -0
- package/dist/auth_flow_ui.js +159 -0
- package/dist/mcp-preview-panel.d.ts +30 -0
- package/dist/mcp-preview-panel.js +166 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +1132 -0
- package/dist/user_auth_flow.d.ts +11 -0
- package/dist/user_auth_flow.js +251 -0
- package/package.json +53 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 PreMan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# PreMan MCP
|
|
2
|
+
|
|
3
|
+
Turn your APIs into MCP tools that coding agents can discover, call, test, and audit.
|
|
4
|
+
|
|
5
|
+
PreMan is agent-first API infrastructure. It lets backend teams expose endpoints to AI coding agents through MCP, add an auth layer around those tools, and see exactly which agent called what.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx premanmcp install
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
This writes an `preman` MCP server into `~/.cursor/mcp.json`:
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"mcpServers": {
|
|
18
|
+
"preman": {
|
|
19
|
+
"command": "npx",
|
|
20
|
+
"args": ["-y", "premanmcp"],
|
|
21
|
+
"env": {
|
|
22
|
+
"PREMAN_API_KEY": "pm_live_YOUR_API_KEY_HERE",
|
|
23
|
+
"PREMAN_BACKEND": "https://api.preman.live",
|
|
24
|
+
"PREMAN_FRONTEND": "https://app.preman.live"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Replace `pm_live_YOUR_API_KEY_HERE` with an API key from [PreMan settings](https://app.preman.live/settings/), then restart Cursor or toggle the MCP server off/on.
|
|
32
|
+
|
|
33
|
+
You can also pass the key directly:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npx premanmcp install --api-key pm_live_xxx
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
For project-local installation:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npx premanmcp install --project
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## What It Does
|
|
46
|
+
|
|
47
|
+
- Converts API endpoints into agent-callable MCP tools.
|
|
48
|
+
- Lets agents test real backend endpoints from the IDE.
|
|
49
|
+
- Syncs endpoint inventory across backend and frontend workflows.
|
|
50
|
+
- Adds API-key auth for PreMan MCP access.
|
|
51
|
+
- Supports hosted MCPs with consumer tokens for customer-facing agent access.
|
|
52
|
+
- Records per-call observability so teams can audit which agent did what.
|
|
53
|
+
|
|
54
|
+
## Common Agent Commands
|
|
55
|
+
|
|
56
|
+
After installing, ask your coding agent:
|
|
57
|
+
|
|
58
|
+
```text
|
|
59
|
+
Use the PreMan MCP to convert my login endpoint into an MCP tool.
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
Use PreMan to test POST /auth/login.
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
```text
|
|
67
|
+
Convert these endpoints into an MCP.
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
```text
|
|
71
|
+
Show me the audit log for this hosted MCP.
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Cursor
|
|
75
|
+
|
|
76
|
+
The installer targets Cursor by default:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
npx premanmcp install
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Manual Cursor config:
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"mcpServers": {
|
|
87
|
+
"preman": {
|
|
88
|
+
"command": "npx",
|
|
89
|
+
"args": ["-y", "premanmcp"],
|
|
90
|
+
"env": {
|
|
91
|
+
"PREMAN_API_KEY": "pm_live_YOUR_API_KEY_HERE"
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Claude Code
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
claude mcp add preman -- npx -y premanmcp
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## CLI
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
npx premanmcp # Start the MCP server
|
|
108
|
+
npx premanmcp install # Install Cursor MCP config
|
|
109
|
+
npx premanmcp install --print # Print config without writing
|
|
110
|
+
npx premanmcp install --project # Write .cursor/mcp.json in current repo
|
|
111
|
+
npx premanmcp install --api-key KEY # Install with your PreMan API key
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Options:
|
|
115
|
+
|
|
116
|
+
- `--api-key <key>`: PreMan API key.
|
|
117
|
+
- `--backend <url>`: PreMan backend URL. Defaults to `https://api.preman.live`.
|
|
118
|
+
- `--frontend <url>`: PreMan frontend URL. Defaults to `https://app.preman.live`.
|
|
119
|
+
- `--name <name>`: MCP server name. Defaults to `preman`.
|
|
120
|
+
- `--project`: Write `.cursor/mcp.json` in the current project.
|
|
121
|
+
- `--print`: Print the generated MCP config without writing it.
|
|
122
|
+
|
|
123
|
+
## Environment Variables
|
|
124
|
+
|
|
125
|
+
- `PREMAN_API_KEY`: PreMan API key.
|
|
126
|
+
- `PREMAN_BACKEND`: PreMan backend URL.
|
|
127
|
+
- `PREMAN_FRONTEND`: PreMan frontend URL.
|
|
128
|
+
|
|
129
|
+
## Product
|
|
130
|
+
|
|
131
|
+
PreMan helps teams make APIs usable by agents without giving up control. Developers can turn endpoints into MCP servers, hand customers an install snippet or hosted MCP URL, and audit every tool call through PreMan.
|
|
132
|
+
|
|
133
|
+
Dashboard: [https://app.preman.live](https://app.preman.live)
|
|
134
|
+
|
|
135
|
+
## License
|
|
136
|
+
|
|
137
|
+
MIT
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* PreMan CLI.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* npx premanmcp install
|
|
8
|
+
* npx premanmcp install --api-key pm_live_xxx
|
|
9
|
+
* npx premanmcp
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { spawn } from "node:child_process";
|
|
13
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
14
|
+
import os from "node:os";
|
|
15
|
+
import path from "node:path";
|
|
16
|
+
import { fileURLToPath } from "node:url";
|
|
17
|
+
|
|
18
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
const ROOT = path.join(__dirname, "..");
|
|
20
|
+
const DEFAULT_BACKEND = "https://api.preman.live";
|
|
21
|
+
const DEFAULT_FRONTEND = "https://app.preman.live";
|
|
22
|
+
const API_KEY_PLACEHOLDER = "pm_live_YOUR_API_KEY_HERE";
|
|
23
|
+
|
|
24
|
+
const args = process.argv.slice(2);
|
|
25
|
+
const command = args[0] === "--help" || args[0] === "-h"
|
|
26
|
+
? "help"
|
|
27
|
+
: args[0] && !args[0].startsWith("-")
|
|
28
|
+
? args[0]
|
|
29
|
+
: "start";
|
|
30
|
+
const commandArgs = command === "start" ? args : args.slice(1);
|
|
31
|
+
|
|
32
|
+
function argValue(name, fallback = "") {
|
|
33
|
+
const index = commandArgs.indexOf(name);
|
|
34
|
+
if (index === -1) return fallback;
|
|
35
|
+
return commandArgs[index + 1] || fallback;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function hasFlag(name) {
|
|
39
|
+
return commandArgs.includes(name);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function printHelp() {
|
|
43
|
+
process.stdout.write(`PreMan MCP
|
|
44
|
+
|
|
45
|
+
Usage:
|
|
46
|
+
npx premanmcp install [options] Install PreMan into Cursor MCP config
|
|
47
|
+
npx premanmcp Start the PreMan MCP server
|
|
48
|
+
|
|
49
|
+
Install options:
|
|
50
|
+
--api-key <key> PreMan API key. Defaults to ${API_KEY_PLACEHOLDER}
|
|
51
|
+
--backend <url> PreMan backend URL. Defaults to ${DEFAULT_BACKEND}
|
|
52
|
+
--frontend <url> PreMan frontend URL. Defaults to ${DEFAULT_FRONTEND}
|
|
53
|
+
--name <name> MCP server name. Defaults to preman
|
|
54
|
+
--project Write .cursor/mcp.json in the current project
|
|
55
|
+
--global Write ~/.cursor/mcp.json (default)
|
|
56
|
+
--print Print the config instead of writing it
|
|
57
|
+
|
|
58
|
+
Examples:
|
|
59
|
+
npx premanmcp install
|
|
60
|
+
npx premanmcp install --api-key pm_live_xxx
|
|
61
|
+
npx premanmcp install --project --backend http://127.0.0.1:8000
|
|
62
|
+
`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function readJsonFile(filePath) {
|
|
66
|
+
if (!existsSync(filePath)) return {};
|
|
67
|
+
const raw = readFileSync(filePath, "utf8").trim();
|
|
68
|
+
if (!raw) return {};
|
|
69
|
+
try {
|
|
70
|
+
return JSON.parse(raw);
|
|
71
|
+
} catch (error) {
|
|
72
|
+
throw new Error(`Could not parse ${filePath}: ${error.message}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function buildServerConfig() {
|
|
77
|
+
const apiKey = argValue("--api-key", process.env.PREMAN_API_KEY || API_KEY_PLACEHOLDER);
|
|
78
|
+
const backend = argValue("--backend", process.env.PREMAN_BACKEND || DEFAULT_BACKEND);
|
|
79
|
+
const frontend = argValue("--frontend", process.env.PREMAN_FRONTEND || DEFAULT_FRONTEND);
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
command: "npx",
|
|
83
|
+
args: ["-y", "premanmcp"],
|
|
84
|
+
env: {
|
|
85
|
+
PREMAN_API_KEY: apiKey,
|
|
86
|
+
PREMAN_BACKEND: backend,
|
|
87
|
+
PREMAN_FRONTEND: frontend,
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function installCursorMcp() {
|
|
93
|
+
const serverName = argValue("--name", "preman");
|
|
94
|
+
const projectInstall = hasFlag("--project");
|
|
95
|
+
const serverConfig = buildServerConfig();
|
|
96
|
+
|
|
97
|
+
if (hasFlag("--print")) {
|
|
98
|
+
process.stdout.write(`${JSON.stringify({ mcpServers: { [serverName]: serverConfig } }, null, 2)}\n`);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const configPath = projectInstall
|
|
103
|
+
? path.join(process.cwd(), ".cursor", "mcp.json")
|
|
104
|
+
: path.join(os.homedir(), ".cursor", "mcp.json");
|
|
105
|
+
|
|
106
|
+
const config = {
|
|
107
|
+
...readJsonFile(configPath),
|
|
108
|
+
};
|
|
109
|
+
config.mcpServers = {
|
|
110
|
+
...(config.mcpServers || {}),
|
|
111
|
+
[serverName]: serverConfig,
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const rendered = `${JSON.stringify(config, null, 2)}\n`;
|
|
115
|
+
mkdirSync(path.dirname(configPath), { recursive: true });
|
|
116
|
+
writeFileSync(configPath, rendered, { mode: 0o600 });
|
|
117
|
+
|
|
118
|
+
const usedPlaceholder = config.mcpServers[serverName].env.PREMAN_API_KEY === API_KEY_PLACEHOLDER;
|
|
119
|
+
process.stdout.write(`PreMan MCP installed in ${configPath}
|
|
120
|
+
|
|
121
|
+
Server name: ${serverName}
|
|
122
|
+
Backend: ${config.mcpServers[serverName].env.PREMAN_BACKEND}
|
|
123
|
+
|
|
124
|
+
Next steps:
|
|
125
|
+
1. ${usedPlaceholder ? `Replace ${API_KEY_PLACEHOLDER} with your PreMan API key in ${configPath}. Find or create one at https://app.preman.live/settings/.` : "Your PreMan API key was written to the MCP config."}
|
|
126
|
+
2. Restart Cursor or toggle the PreMan MCP server off/on.
|
|
127
|
+
3. Ask your agent: "Use the PreMan MCP to convert my login endpoint into an MCP tool." Then open https://app.preman.live/ to see the session and generated MCP.
|
|
128
|
+
`);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function startServer() {
|
|
132
|
+
const serverPath = path.join(ROOT, "dist", "server.js");
|
|
133
|
+
if (!existsSync(serverPath)) {
|
|
134
|
+
process.stderr.write(`[preman] MCP server not found at ${serverPath}. Run npm run build before publishing.\n`);
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const env = { ...process.env };
|
|
139
|
+
const apiKey = argValue("--api-key", argValue("--key", ""));
|
|
140
|
+
const backend = argValue("--backend", "");
|
|
141
|
+
const frontend = argValue("--frontend", "");
|
|
142
|
+
if (apiKey) env.PREMAN_API_KEY = apiKey;
|
|
143
|
+
if (backend) env.PREMAN_BACKEND = backend;
|
|
144
|
+
if (frontend) env.PREMAN_FRONTEND = frontend;
|
|
145
|
+
if (hasFlag("--local")) env.PREMAN_BACKEND = "";
|
|
146
|
+
|
|
147
|
+
const child = spawn(process.execPath, [serverPath, ...commandArgs], {
|
|
148
|
+
env,
|
|
149
|
+
stdio: "inherit",
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
child.on("exit", (code, signal) => {
|
|
153
|
+
if (signal) process.kill(process.pid, signal);
|
|
154
|
+
process.exit(code || 0);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (command === "install") {
|
|
159
|
+
installCursorMcp();
|
|
160
|
+
} else if (command === "help" || command === "--help" || command === "-h") {
|
|
161
|
+
printHelp();
|
|
162
|
+
} else if (command === "start") {
|
|
163
|
+
startServer();
|
|
164
|
+
} else {
|
|
165
|
+
process.stderr.write(`Unknown command: ${command}\n\n`);
|
|
166
|
+
printHelp();
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth flow endpoints (signup, verify OTP, login, resend OTP) with JSON schemas
|
|
3
|
+
* for share_endpoints_with_ui / agent-sessions push.
|
|
4
|
+
*/
|
|
5
|
+
export type AuthFlowEndpoint = {
|
|
6
|
+
method: string;
|
|
7
|
+
path_template: string;
|
|
8
|
+
description: string;
|
|
9
|
+
tags: string[];
|
|
10
|
+
source_file: string;
|
|
11
|
+
request_body_schema: Record<string, unknown>;
|
|
12
|
+
response_schema: Record<string, unknown>;
|
|
13
|
+
mcp_tool?: string;
|
|
14
|
+
};
|
|
15
|
+
/** Core auth endpoints aligned with routes/auth/routes.py and user_auth_* MCP tools. */
|
|
16
|
+
export declare function buildAuthFlowEndpoints(): AuthFlowEndpoint[];
|
|
17
|
+
export type ShareAuthFlowResult = {
|
|
18
|
+
session_id: string;
|
|
19
|
+
url: string;
|
|
20
|
+
endpoint_count: number;
|
|
21
|
+
upstream_base_url: string;
|
|
22
|
+
endpoints: AuthFlowEndpoint[];
|
|
23
|
+
ui: {
|
|
24
|
+
url: string;
|
|
25
|
+
note: string;
|
|
26
|
+
};
|
|
27
|
+
related_tools: string[];
|
|
28
|
+
};
|
|
29
|
+
export declare function shareAuthFlowToUi(opts: {
|
|
30
|
+
backendUrl: string;
|
|
31
|
+
frontendUrl: string;
|
|
32
|
+
upstreamBaseUrl?: string;
|
|
33
|
+
sessionId?: string;
|
|
34
|
+
intent?: string;
|
|
35
|
+
}): Promise<ShareAuthFlowResult>;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth flow endpoints (signup, verify OTP, login, resend OTP) with JSON schemas
|
|
3
|
+
* for share_endpoints_with_ui / agent-sessions push.
|
|
4
|
+
*/
|
|
5
|
+
const EMAIL_PROP = { type: "string", format: "email", description: "User email" };
|
|
6
|
+
const PASSWORD_PROP = {
|
|
7
|
+
type: "string",
|
|
8
|
+
minLength: 6,
|
|
9
|
+
description: "Password (min 6 characters on the server)",
|
|
10
|
+
};
|
|
11
|
+
const OTP_PROP = { type: "string", description: "6-digit code from email" };
|
|
12
|
+
const TOKEN_RESPONSE = {
|
|
13
|
+
type: "object",
|
|
14
|
+
properties: {
|
|
15
|
+
access_token: { type: "string", description: "JWT bearer token" },
|
|
16
|
+
token_type: { type: "string", enum: ["bearer"] },
|
|
17
|
+
user: {
|
|
18
|
+
type: "object",
|
|
19
|
+
properties: {
|
|
20
|
+
id: { type: "string" },
|
|
21
|
+
email: { type: "string", format: "email" },
|
|
22
|
+
},
|
|
23
|
+
required: ["id", "email"],
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
required: ["access_token", "token_type", "user"],
|
|
27
|
+
};
|
|
28
|
+
const OTP_SENT_RESPONSE = {
|
|
29
|
+
type: "object",
|
|
30
|
+
properties: {
|
|
31
|
+
message: { type: "string" },
|
|
32
|
+
email_sent: { type: "boolean" },
|
|
33
|
+
},
|
|
34
|
+
required: ["message", "email_sent"],
|
|
35
|
+
};
|
|
36
|
+
/** Core auth endpoints aligned with routes/auth/routes.py and user_auth_* MCP tools. */
|
|
37
|
+
export function buildAuthFlowEndpoints() {
|
|
38
|
+
return [
|
|
39
|
+
{
|
|
40
|
+
method: "POST",
|
|
41
|
+
path_template: "/auth/signup",
|
|
42
|
+
description: "Register with email and password. Sends OTP to email; next: verify-otp.",
|
|
43
|
+
tags: ["auth", "signup"],
|
|
44
|
+
source_file: "routes/auth/routes.py",
|
|
45
|
+
mcp_tool: "user_auth_signup",
|
|
46
|
+
request_body_schema: {
|
|
47
|
+
type: "object",
|
|
48
|
+
properties: { email: EMAIL_PROP, password: PASSWORD_PROP },
|
|
49
|
+
required: ["email", "password"],
|
|
50
|
+
additionalProperties: false,
|
|
51
|
+
},
|
|
52
|
+
response_schema: {
|
|
53
|
+
type: "object",
|
|
54
|
+
properties: {
|
|
55
|
+
message: { type: "string" },
|
|
56
|
+
user_id: { type: "string" },
|
|
57
|
+
email: { type: "string", format: "email" },
|
|
58
|
+
email_sent: { type: "boolean" },
|
|
59
|
+
},
|
|
60
|
+
required: ["message", "user_id", "email", "email_sent"],
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
method: "POST",
|
|
65
|
+
path_template: "/auth/verify-otp",
|
|
66
|
+
description: "Verify email OTP after signup; returns JWT access_token.",
|
|
67
|
+
tags: ["auth", "otp"],
|
|
68
|
+
source_file: "routes/auth/routes.py",
|
|
69
|
+
mcp_tool: "user_auth_verify_otp",
|
|
70
|
+
request_body_schema: {
|
|
71
|
+
type: "object",
|
|
72
|
+
properties: { email: EMAIL_PROP, otp: OTP_PROP },
|
|
73
|
+
required: ["email", "otp"],
|
|
74
|
+
additionalProperties: false,
|
|
75
|
+
},
|
|
76
|
+
response_schema: TOKEN_RESPONSE,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
method: "POST",
|
|
80
|
+
path_template: "/auth/login",
|
|
81
|
+
description: "Login with email and password. Returns access_token if email is verified.",
|
|
82
|
+
tags: ["auth", "login"],
|
|
83
|
+
source_file: "routes/auth/routes.py",
|
|
84
|
+
mcp_tool: "user_auth_login",
|
|
85
|
+
request_body_schema: {
|
|
86
|
+
type: "object",
|
|
87
|
+
properties: { email: EMAIL_PROP, password: PASSWORD_PROP },
|
|
88
|
+
required: ["email", "password"],
|
|
89
|
+
additionalProperties: false,
|
|
90
|
+
},
|
|
91
|
+
response_schema: TOKEN_RESPONSE,
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
method: "POST",
|
|
95
|
+
path_template: "/auth/resend-otp",
|
|
96
|
+
description: "Send (resend) verification OTP to email.",
|
|
97
|
+
tags: ["auth", "otp"],
|
|
98
|
+
source_file: "routes/auth/routes.py",
|
|
99
|
+
mcp_tool: "user_auth_resend_otp",
|
|
100
|
+
request_body_schema: {
|
|
101
|
+
type: "object",
|
|
102
|
+
properties: { email: EMAIL_PROP },
|
|
103
|
+
required: ["email"],
|
|
104
|
+
additionalProperties: false,
|
|
105
|
+
},
|
|
106
|
+
response_schema: OTP_SENT_RESPONSE,
|
|
107
|
+
},
|
|
108
|
+
];
|
|
109
|
+
}
|
|
110
|
+
export async function shareAuthFlowToUi(opts) {
|
|
111
|
+
const backend = opts.backendUrl.replace(/\/+$/, "");
|
|
112
|
+
const frontend = opts.frontendUrl.replace(/\/+$/, "");
|
|
113
|
+
const upstream = (opts.upstreamBaseUrl || backend).replace(/\/+$/, "") || backend;
|
|
114
|
+
const sessionId = opts.sessionId?.trim() || crypto.randomUUID();
|
|
115
|
+
const endpoints = buildAuthFlowEndpoints().map((ep) => ({
|
|
116
|
+
...ep,
|
|
117
|
+
base_url: upstream,
|
|
118
|
+
}));
|
|
119
|
+
const resp = await fetch(`${backend}/agent-sessions/${encodeURIComponent(sessionId)}/endpoints`, {
|
|
120
|
+
method: "POST",
|
|
121
|
+
headers: { "Content-Type": "application/json", Accept: "application/json" },
|
|
122
|
+
body: JSON.stringify({
|
|
123
|
+
endpoints,
|
|
124
|
+
upstream_base_url: upstream,
|
|
125
|
+
intent: opts.intent || "Auth flow: signup, verify OTP, login, resend OTP",
|
|
126
|
+
}),
|
|
127
|
+
});
|
|
128
|
+
const text = await resp.text();
|
|
129
|
+
let body = {};
|
|
130
|
+
try {
|
|
131
|
+
body = text ? JSON.parse(text) : {};
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
throw new Error(`Agent session push failed: ${resp.status} ${text.slice(0, 500)}`);
|
|
135
|
+
}
|
|
136
|
+
if (!resp.ok) {
|
|
137
|
+
throw new Error(String(body.detail ?? body.error ?? `Agent session push failed: ${resp.status}`));
|
|
138
|
+
}
|
|
139
|
+
const sid = String(body.id ?? sessionId);
|
|
140
|
+
const url = `${frontend}/try?session=${encodeURIComponent(sid)}`;
|
|
141
|
+
return {
|
|
142
|
+
session_id: sid,
|
|
143
|
+
url,
|
|
144
|
+
endpoint_count: Number(body.endpoint_count ?? endpoints.length),
|
|
145
|
+
upstream_base_url: upstream,
|
|
146
|
+
endpoints: buildAuthFlowEndpoints(),
|
|
147
|
+
ui: {
|
|
148
|
+
url,
|
|
149
|
+
note: "Open in Cursor Agent Browser. Test signup → verify-otp → login, or resend-otp. " +
|
|
150
|
+
"Schemas are prefilled from routes/auth Pydantic models.",
|
|
151
|
+
},
|
|
152
|
+
related_tools: [
|
|
153
|
+
"user_auth_signup",
|
|
154
|
+
"user_auth_verify_otp",
|
|
155
|
+
"user_auth_login",
|
|
156
|
+
"user_auth_resend_otp",
|
|
157
|
+
],
|
|
158
|
+
};
|
|
159
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export declare const MCP_PREVIEW_RESOURCE_URI = "ui://preman/mcp-preview";
|
|
2
|
+
export declare const RESOURCE_URI_META_KEY = "ui/resourceUri";
|
|
3
|
+
export declare function escapeHtmlAttr(s: string): string;
|
|
4
|
+
export declare function escapeHtmlText(s: string): string;
|
|
5
|
+
export interface PreviewTool {
|
|
6
|
+
name?: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
inputSchema?: unknown;
|
|
9
|
+
_endpoint_ref?: {
|
|
10
|
+
method?: string;
|
|
11
|
+
path_template?: string;
|
|
12
|
+
tags?: string[];
|
|
13
|
+
source?: string;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export interface PreviewPayload {
|
|
17
|
+
intent?: string | string[];
|
|
18
|
+
selection_method?: string | string[];
|
|
19
|
+
rationale?: string | string[] | Record<string, string>;
|
|
20
|
+
selected_count?: number;
|
|
21
|
+
spec_preview?: {
|
|
22
|
+
upstream_base_url?: string | string[];
|
|
23
|
+
tools?: PreviewTool[];
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export declare function buildConversionPanelHtml(data: PreviewPayload): string;
|
|
27
|
+
export declare function writeMcpPreviewFile(panelHtml: string): Promise<{
|
|
28
|
+
absolutePath: string;
|
|
29
|
+
fileUrl: string;
|
|
30
|
+
}>;
|