premanmcp 0.10.5 → 0.10.7
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 +35 -7
- package/bin/account.js +19 -4
- package/bin/api_tools.js +1 -1
- package/bin/cli.js +22 -5
- package/bin/connect/agents.js +198 -0
- package/bin/connect/checkin.js +503 -0
- package/bin/connect/configs.js +276 -0
- package/bin/connect/dispatch.js +131 -0
- package/bin/connect/errors.js +16 -0
- package/bin/connect/guide.js +523 -0
- package/bin/connect/pairing.js +94 -0
- package/bin/connect.js +101 -1508
- package/bin/desktop.js +1 -1
- package/bin/detect.js +42 -3
- package/bin/hook.js +126 -2
- package/bin/hosted.js +4 -4
- package/bin/progress.js +2 -5
- package/bin/runner.js +25 -36
- package/bin/shared.js +26 -1
- package/bin/status.js +1 -6
- package/bin/tests.js +341 -0
- package/bin/verify.js +82 -54
- package/dist/server.js +78 -0
- package/package.json +2 -2
package/dist/server.js
CHANGED
|
@@ -3,10 +3,12 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { registerUserAuthFlowTools } from "./user_auth_flow.js";
|
|
5
5
|
import { shareAuthFlowToUi } from "./auth_flow_ui.js";
|
|
6
|
+
import { spawn } from "node:child_process";
|
|
6
7
|
import { existsSync, readFileSync } from "node:fs";
|
|
7
8
|
import fs from "node:fs/promises";
|
|
8
9
|
import path from "node:path";
|
|
9
10
|
import os from "node:os";
|
|
11
|
+
import { fileURLToPath } from "node:url";
|
|
10
12
|
import { randomUUID } from "node:crypto";
|
|
11
13
|
import { MCP_PREVIEW_RESOURCE_URI, RESOURCE_URI_META_KEY, buildConversionPanelHtml, writeMcpPreviewFile, } from "./mcp-preview-panel.js";
|
|
12
14
|
let REPO_CONFIG = null;
|
|
@@ -391,6 +393,7 @@ export function createServer() {
|
|
|
391
393
|
"- 'preview my MCP before deploying': mcp_preview (read-only). 'actually deploy': mcp_deploy.",
|
|
392
394
|
"- 'test the login endpoint' / 'hit POST /auth/login with body': test_api with the full URL. Use test_endpoint_by_id ONLY when the user references a saved endpoint by id/uuid.",
|
|
393
395
|
"- 'import my Postman/OpenAPI/Bruno/curl collection': import_collection.",
|
|
396
|
+
"- 'migrate / move / switch from Postman', 'bring my Postman workspace over': migrate_from_postman — it imports AND creates scheduled suites, environments and alerts in one call. Prefer it over import_collection whenever the user frames this as leaving Postman.",
|
|
394
397
|
"- 'generate tests for endpoint X' / 'write unit tests for X and run them': generate_endpoint_tests (set include_code=true and write the returned code_artifacts to disk when the user wants test files).",
|
|
395
398
|
"- 'stress / load test X': run_stress_test. Read-only unless the user explicitly authorises writes — never set allow_writes yourself.",
|
|
396
399
|
"- After discover_endpoints_from_codebase, call register_discovered_endpoints with the JSON array it asked for, then verify_endpoints_live to confirm they respond.",
|
|
@@ -408,6 +411,7 @@ export function createServer() {
|
|
|
408
411
|
"2. **Import then generate**: import_collection (Postman/OpenAPI/curl) -> generate_tests -> test_api to run them.",
|
|
409
412
|
'3. **Coverage audit**: get_coverage on a collection -> generate_tests(coverage_level="comprehensive") for gaps.',
|
|
410
413
|
"4. **Drift detection**: detect_drift with a collection + base_url -> test_api on drifted endpoints.",
|
|
414
|
+
"5. **Postman migration**: migrate_from_postman -> review next_steps (base URLs, secrets needing values) -> re-run with activate=true -> failures open fix tasks you collect with preman_get_fix_task.",
|
|
411
415
|
"",
|
|
412
416
|
"## Auth",
|
|
413
417
|
"PreMan API tools (get_endpoints, test_api, …) need an pm_live_ key. Preferred no-browser flow: user_auth_start_signup -> user_auth_set_password -> preman_create_api_key, or user_auth_login -> preman_create_api_key. Browser fallback: preman_login -> preman_login_complete.",
|
|
@@ -663,6 +667,57 @@ export function createServer() {
|
|
|
663
667
|
});
|
|
664
668
|
}
|
|
665
669
|
});
|
|
670
|
+
// ── migrate_from_postman ──────────────────────────────────────────
|
|
671
|
+
server.tool("migrate_from_postman", "Move a Postman collection into PreMan, fully wired, in one call. Converts the collection keeping the assertions its pm.test blocks declared, splits the environment into shared variables and encrypted secrets, and creates one scheduled test suite per request seeded from those assertions. Suites are created switched OFF; pass activate=true to start them and attach alert rules so a failing check opens a fix task. Returns next_steps — the honest list of what still needs a human.", {
|
|
672
|
+
content: z.string().optional().describe("Raw Postman collection export (v2.x JSON)"),
|
|
673
|
+
collection_id: z.string().optional().describe("Pull from a connected Postman workspace instead of pasting content"),
|
|
674
|
+
environment: z.string().optional().describe("Raw Postman environment export (JSON)"),
|
|
675
|
+
name: z.string().optional().describe("Override the collection name"),
|
|
676
|
+
project_id: z.string().optional().describe("Scope the migration to a project"),
|
|
677
|
+
activate: z.boolean().optional().default(false).describe("Start the suites and create alert rules. Leave false to review first."),
|
|
678
|
+
channel_ids: z.array(z.string()).optional().describe("Alert channels to notify. Empty still records events and opens fix tasks."),
|
|
679
|
+
autofix_enabled: z.boolean().optional().default(false).describe("Let a failure dispatch to the coding agent automatically"),
|
|
680
|
+
include_yaml: z.boolean().optional().default(false).describe("Include the full .ot.yaml string (default false to save tokens)"),
|
|
681
|
+
}, async (args) => {
|
|
682
|
+
try {
|
|
683
|
+
const result = await callBackend("migrate_from_postman", args);
|
|
684
|
+
const collectionId = result?.collection_id ?? "";
|
|
685
|
+
const dashPath = collectionId ? `/collections?id=${collectionId}` : "/collections";
|
|
686
|
+
emitActivity("navigate", { path: dashPath });
|
|
687
|
+
emitActivity("data_refresh", { scope: "collections" });
|
|
688
|
+
return withFrontendUrl({ ...result, ...agentSessionPayload(dashPath) }, dashPath);
|
|
689
|
+
}
|
|
690
|
+
catch (e) {
|
|
691
|
+
return toolError(e.message, inferErrorCode(e.message), {
|
|
692
|
+
next_actions: [
|
|
693
|
+
"Provide either content (a Postman v2.x export) or collection_id from a connected Postman workspace.",
|
|
694
|
+
"Connect a workspace at /integrations/postman/connect to use collection_id.",
|
|
695
|
+
],
|
|
696
|
+
related_tools: ["import_collection", "get_endpoints"],
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
});
|
|
700
|
+
// ── recover_assertions ────────────────────────────────────────────
|
|
701
|
+
server.tool("recover_assertions", "Hand back assertions you translated from a Postman script PreMan could not read. An import's migration_report lists every dropped pm.test block with the script attached under entries[].source — read that JavaScript, convert what it checks, and call this. The assertion lands on the collection endpoint, its workbench request and the scheduled suite, so the next run grades it. Each assertion accepts: status (int or '2xx'), status_not (int), response_time_ms ('< 500'), json_paths ({'json.id': 7}, or 'exists' to require a field).", {
|
|
702
|
+
collection_id: z.string().describe("The collection the import created"),
|
|
703
|
+
endpoint_id: z.string().describe("entries[].endpoint_id from the migration report (or the endpoint name)"),
|
|
704
|
+
assertions: z.array(z.record(z.any())).describe("The converted assertions"),
|
|
705
|
+
}, async (args) => {
|
|
706
|
+
try {
|
|
707
|
+
const result = await callBackend("recover_assertions", args);
|
|
708
|
+
emitActivity("data_refresh", { scope: "collections" });
|
|
709
|
+
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
|
710
|
+
}
|
|
711
|
+
catch (e) {
|
|
712
|
+
return toolError(e.message, inferErrorCode(e.message), {
|
|
713
|
+
next_actions: [
|
|
714
|
+
"Check collection_id and endpoint_id against the migration_report entries.",
|
|
715
|
+
"Each assertion must use the documented fields: status, status_not, response_time_ms, json_paths.",
|
|
716
|
+
],
|
|
717
|
+
related_tools: ["get_collection", "migrate_from_postman"],
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
});
|
|
666
721
|
// ── detect_drift ──────────────────────────────────────────────────
|
|
667
722
|
server.tool("detect_drift", "Detect spec drift by comparing live API responses against a collection spec. Returns a list of drift alerts per endpoint with expected vs actual differences.", {
|
|
668
723
|
base_url: z.string().describe("Base URL to test against (e.g. https://api.example.com)"),
|
|
@@ -1444,11 +1499,34 @@ export function createServer() {
|
|
|
1444
1499
|
return server;
|
|
1445
1500
|
}
|
|
1446
1501
|
// ── Start ─────────────────────────────────────────────────────────────
|
|
1502
|
+
/**
|
|
1503
|
+
* A pre-push hook PreMan wrote can stop working — the machine gained a `preman`
|
|
1504
|
+
* belonging to another package, or lost the one it pinned — and the only symptom
|
|
1505
|
+
* is one skipped line per push. This process starting is proof PreMan runs here,
|
|
1506
|
+
* so it is a good moment to check. Detached with stdio ignored: the check shells
|
|
1507
|
+
* out to npm, and this process's stdout is the MCP protocol.
|
|
1508
|
+
*/
|
|
1509
|
+
function repairPushHookInBackground() {
|
|
1510
|
+
try {
|
|
1511
|
+
const cli = path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "bin", "cli.js");
|
|
1512
|
+
if (!existsSync(cli))
|
|
1513
|
+
return;
|
|
1514
|
+
const child = spawn(process.execPath, [cli, "hook", "repair", "--if-stale"], {
|
|
1515
|
+
detached: true,
|
|
1516
|
+
stdio: "ignore",
|
|
1517
|
+
});
|
|
1518
|
+
child.unref();
|
|
1519
|
+
}
|
|
1520
|
+
catch {
|
|
1521
|
+
// Never worth failing a server start over.
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1447
1524
|
async function main() {
|
|
1448
1525
|
await initAuth();
|
|
1449
1526
|
const server = createServer();
|
|
1450
1527
|
const transport = new StdioServerTransport();
|
|
1451
1528
|
await server.connect(transport);
|
|
1529
|
+
repairPushHookInBackground();
|
|
1452
1530
|
// Starting the configured MCP server is itself proof that the coding agent
|
|
1453
1531
|
// is live. Previously the workbench remained in `connecting` until someone
|
|
1454
1532
|
// explicitly asked the agent to call `preman_status`, even when this process
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "premanmcp",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.7",
|
|
4
4
|
"description": "Turn APIs into agent-callable MCP tools with auth, testing, and audit logs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"open-mcp-preview-in-cursor": "node scripts/open-cursor-preview.mjs",
|
|
16
16
|
"test": "npm run build && npm run test:connect && npm run test:node",
|
|
17
17
|
"test:connect": "node scripts/smoke-connect.mjs",
|
|
18
|
-
"test:node": "node --test --test-timeout=
|
|
18
|
+
"test:node": "node --test --test-timeout=90000 scripts/smoke-account.mjs scripts/smoke-cli-entrypoint.mjs scripts/smoke-launcher-config.mjs scripts/smoke-runner.mjs scripts/smoke-repo-config.mjs scripts/smoke-onboard.mjs scripts/smoke-local-detect.mjs scripts/smoke-prepush-hook.mjs scripts/smoke-cli-identity.mjs scripts/smoke-runner-heartbeat.mjs scripts/smoke-verify-prepush.mjs scripts/smoke-push-diff.mjs scripts/smoke-progress-reporter.mjs scripts/smoke-verify-plan.mjs scripts/smoke-install-desktop.mjs scripts/smoke-api-tools.mjs scripts/smoke-tests-workbench.mjs scripts/smoke-bin-scope.mjs"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@modelcontextprotocol/ext-apps": "^0.1.0",
|