diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 9dc194b..00feffe 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "postman", - "version": "1.3.0", + "version": "1.4.0", "description": "Full API lifecycle management for Claude Code. Sync collections, generate client code, discover APIs, run tests, create mocks, publish docs, and audit security. Powered by the Postman MCP Server.", "author": { "name": "Postman", diff --git a/CHANGELOG.md b/CHANGELOG.md index 065328b..77f320c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,23 @@ is cut by tagging the matching `vX.Y.Z` (see [Releasing](#releasing)). ## [Unreleased] +## [1.4.0] - 2026-08-02 + +### Added + +- `/postman:use-local` and `/postman:use-remote` commands — toggle which Postman + MCP Server this plugin talks to by rewriting the bundled `.mcp.json` in place. + `use-remote` points it at the hosted server (`https://mcp.postman.com/mcp`, Full + mode, OAuth); `use-local` points it at the local stdio package + (`npx @postman/postman-mcp-server@latest`, which requires `POSTMAN_API_KEY`). + Added for cross-plugin command parity with the Cursor and Antigravity plugins. +- `/postman:generate-client` command — generates typed client code from a + Postman collection. This is the inverse of `/postman:generate-spec` (which + authors an OpenAPI spec from code). Reads the collection through the MCP + codegen tools and writes a production-ready client matching the project's + language and conventions. Requires Full or Code MCP mode (this plugin + defaults to Full). + ## [1.3.0] - 2026-07-20 ### Added @@ -72,7 +89,8 @@ Releases are automated by `.github/workflows/release.yml`. To cut a release: The workflow verifies the tag matches `plugin.json`, extracts the matching CHANGELOG section, and publishes a GitHub Release with those notes. -[Unreleased]: https://github.com/Postman-Devrel/postman-claude-code-plugin/compare/v1.3.0...HEAD +[Unreleased]: https://github.com/Postman-Devrel/postman-claude-code-plugin/compare/v1.4.0...HEAD +[1.4.0]: https://github.com/Postman-Devrel/postman-claude-code-plugin/compare/v1.3.0...v1.4.0 [1.3.0]: https://github.com/Postman-Devrel/postman-claude-code-plugin/compare/v1.2.0...v1.3.0 [1.2.0]: https://github.com/Postman-Devrel/postman-claude-code-plugin/compare/v1.1.0...v1.2.0 [1.1.0]: https://github.com/Postman-Devrel/postman-claude-code-plugin/compare/v1.0.0...v1.1.0 diff --git a/README.md b/README.md index 3b869d0..22da296 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,9 @@ That's it. The plugin auto-configures the Postman MCP Server, verifies your conn | `/postman:docs` | Generate, improve, and publish API documentation | | `/postman:security` | Security audit against OWASP API Top 10 | | `/postman:learn` | Search the Postman Learning Center for how-to guidance and suggested workflows (Full mode) | +| `/postman:generate-client` | Generate typed client code from a Postman collection (Full or Code mode) | +| `/postman:use-remote` | Switch the plugin to the hosted MCP Server (`mcp.postman.com`, Full mode, OAuth) | +| `/postman:use-local` | Switch the plugin to the local stdio MCP Server (`npx @postman/postman-mcp-server`, needs `POSTMAN_API_KEY`) | ## What You Can Do diff --git a/commands/generate-client.md b/commands/generate-client.md new file mode 100644 index 0000000..bd73b92 --- /dev/null +++ b/commands/generate-client.md @@ -0,0 +1,117 @@ +--- +description: Generate typed client code from a Postman collection. Reads your private APIs and writes production-ready client code that matches your project conventions. +allowed-tools: Bash, Read, Write, Glob, Grep, mcp__postman__searchPostmanElements, mcp__postman__getWorkspaces, mcp__postman__getCollections, mcp__postman__getCollection, mcp__postman__getCollectionFolder, mcp__postman__getCollectionRequest, mcp__postman__getCollectionResponse, mcp__postman__getEnvironment, mcp__postman__getSpecDefinition, mcp__postman__getCodeGenerationInstructions +--- + +# Generate Client Code + +Generate typed client code from a Postman collection. Reads your private APIs and writes production-ready client code that matches your project's language and conventions. + +This is the inverse of `/postman:generate-spec` (which authors an OpenAPI spec *from* your code): here the collection is the source of truth and code is the output. + +## Prerequisites + +The Postman MCP Server must be connected. If MCP tools aren't available, tell the user: "Run `/postman:setup` to configure the Postman MCP Server." + +This command's codegen tools (`getCodeGenerationInstructions`, the collection readers) require **Full** or **Code** MCP mode. This plugin defaults to Full mode, so it works out of the box; if the tools are missing, run `/postman:use-remote` (or unset `POSTMAN_MCP_MODE`) and restart Claude Code. + +## Workflow + +### Step 1: Find the API + +1. Call `searchPostmanElements` with the API name and `entityType: collections`. Set `ownership` based on the user's intent: + - `ownership: organization` (default) for the user's org resources. To restrict to the trusted Private API Network, add `filters: {"$and":[{"privateNetwork":{"$eq":true}}]}`. + - `ownership: external` for third-party public APIs. + - `ownership: all` to search everywhere. +2. If results are sparse, broaden the search (widen `ownership`, relax filters) or fall back to `getWorkspaces` + `getCollections` with the `workspace` parameter and `name` filter. +3. Match by name or ask the user which collection to generate code from. +4. Call `getCollection` (full model) to get the complete collection with all requests, bodies, and params. +5. Call `getSpecDefinition` if a linked spec exists (richer type information). +6. Call `getCodeGenerationInstructions` for the MCP server's recommended codegen workflow. + +### Step 2: Understand the API Shape + +For the target collection: +1. Call `getCollectionFolder` for each folder to understand resource grouping. +2. Call `getCollectionRequest` for each relevant endpoint to get: + - HTTP method and URL + - Request headers and auth requirements + - Request body schema + - Path and query parameters +3. Call `getCollectionResponse` for each request to get: + - Response status codes + - Response body shapes (for typing) + - Error response formats +4. Call `getEnvironment` to understand base URLs and variables. + +### Step 3: Detect Project Language + +If the user doesn't specify a language, detect it from the project: + +| File | Language | +|------|----------| +| `package.json` + `tsconfig.json` | TypeScript | +| `package.json` (no tsconfig) | JavaScript | +| `requirements.txt` or `pyproject.toml` | Python | +| `go.mod` | Go | +| `Cargo.toml` | Rust | +| `pom.xml` or `build.gradle` | Java | +| `*.csproj` | C# | +| `Gemfile` | Ruby | + +### Step 4: Generate Code + +Generate a client that includes: + +- **Typed client class or module** with one method per endpoint +- **Request/response types** from the collection schemas and examples +- **Authentication handling** based on collection auth config (Bearer, API key, OAuth2) +- **Error handling** with typed error responses from documented error schemas +- **Environment-based configuration** (base URL from env vars) +- **Pagination support** if the API uses cursor or offset pagination + +The generated code should: +- Match the project's existing conventions (imports, formatting, naming style) +- Include JSDoc, docstrings, or doc comments from collection descriptions +- Use the project's existing HTTP library if one is present (axios, fetch, requests, reqwest, etc.) +- Use proper camelCase/snake_case matching the target language conventions +- Handle query parameters, path parameters, headers, and request bodies correctly + +### Step 5: Write and Present + +Write the generated code to an appropriate location in the project: +- TypeScript/JavaScript: `src/clients/.ts` or `src/lib/.ts` +- Python: `src/clients/.py` or `/clients/.py` +- Go: `pkg/clients/.go` or `internal/clients/.go` + +Present a summary: + +``` +Generated: src/clients/users-api.ts + + Endpoints covered: + GET /users -> getUsers(filters) + GET /users/{id} -> getUser(id) + POST /users -> createUser(data) + PUT /users/{id} -> updateUser(id, data) + DELETE /users/{id} -> deleteUser(id) + + Types generated: + User, CreateUserRequest, UpdateUserRequest, + UserListResponse, ApiError + + Auth: Bearer token (from USERS_API_TOKEN env var) + Base URL: from USERS_API_BASE_URL env var +``` + +## Error Handling + +| Error | Response | +|-------|----------| +| MCP not configured | "Run `/postman:setup` to configure the Postman MCP Server." | +| Codegen tools missing (wrong mode) | "Client generation requires Full or Code MCP mode. Run `/postman:use-remote` (or unset `POSTMAN_MCP_MODE`) and restart Claude Code." | +| Collection not found | "I didn't find a collection matching that name. Run `/postman:search` to see what's available." | +| No requests in collection | "This collection is empty. Add requests in Postman first, or use `/postman:sync` to create from a spec." | +| Can't detect language | "I can't detect the project language. What language should I generate the client in?" | +| Missing auth config | "This collection doesn't specify an auth method. I'll generate the client without auth. You can add it later." | +| Spec not available | "No linked spec found. I'll generate types from the collection's saved examples and request bodies." | diff --git a/commands/use-local.md b/commands/use-local.md new file mode 100644 index 0000000..eb094b7 --- /dev/null +++ b/commands/use-local.md @@ -0,0 +1,66 @@ +--- +description: Switch this plugin's Postman MCP Server to the LOCAL stdio package (npx @postman/postman-mcp-server@latest). Requires POSTMAN_API_KEY. +allowed-tools: Bash, Read, Write +--- + +# Use Local MCP Server + +Point this plugin at the **local** Postman MCP Server — the stdio package run via `npx @postman/postman-mcp-server@latest` — instead of Postman's hosted remote server. This rewrites the plugin's own `.mcp.json` in place, changing only the transport (remote → local). The local server authenticates with a `POSTMAN_API_KEY` read from your environment (there is no OAuth for the local package). + +Switch back to the hosted server at any time with `/postman:use-remote`. + +## Workflow + +### Step 1: Locate this plugin's `.mcp.json` + +The file to rewrite is the `.mcp.json` bundled with this plugin (it lives at the plugin's root, next to `.claude-plugin/`). Find it and show the current content: + +```bash +for f in "$CLAUDE_PLUGIN_ROOT/.mcp.json" "$HOME"/.claude/plugins/*/.mcp.json "$HOME"/.claude/plugins/*/*/.mcp.json; do + [ -f "$f" ] || continue + if grep -q '"postman"' "$f"; then echo "FOUND: $f"; echo "--- current content ---"; cat "$f"; echo; fi +done +``` + +Use the `FOUND:` path as the target file to edit. If nothing is found, stop and ask the user for the path to the installed plugin's `.mcp.json`. + +### Step 2: Verify the API key + +The local server reads a Postman API key from the environment. Check it: + +```bash +if [ -n "$POSTMAN_API_KEY" ]; then echo "POSTMAN_API_KEY is set"; else echo "POSTMAN_API_KEY is NOT set"; fi +``` + +If it is **not** set, tell the user to run `export POSTMAN_API_KEY=PMAK-your-key-here` and add that line to `~/.zshrc` or `~/.bashrc` so it persists, then restart the shell before continuing. They can generate a key at https://go.postman.co/settings/me/api-keys. Never hardcode the key into the file — it is read from the environment. + +### Step 3: Overwrite the target `.mcp.json` + +Write exactly this content to the `FOUND:` path: + +```json +{ + "mcpServers": { + "postman": { + "type": "stdio", + "command": "npx", + "args": ["-y", "@postman/postman-mcp-server@latest"], + "env": { + "POSTMAN_API_KEY": "${POSTMAN_API_KEY}" + } + } + } +} +``` + +The `${POSTMAN_API_KEY}` reference is expanded by Claude Code from your environment (the same expansion the remote config uses for `${POSTMAN_MCP_MODE}`), and the spawned stdio process also inherits your shell environment. To preserve a specific toolset, add the matching mode flag to `args` (e.g. `--full`, `--code`, `--minimal`); with no mode flag the package runs its default toolset. + +### Step 4: Confirm and restart + +Print the new file content back to the user, confirm the switch (remote → local stdio), and tell them to **restart Claude Code** for the change to take effect. Remind them they can switch back to the hosted server at any time with `/postman:use-remote`. + +## Error Handling + +- **`.mcp.json` not found:** Ask the user for the path to the installed plugin's `.mcp.json`, or tell them to reinstall the plugin. +- **`POSTMAN_API_KEY` not set:** Walk through Step 2 — the local server cannot authenticate without it. +- **`npx` unavailable:** The local package needs Node.js. Tell the user to install Node, or switch back with `/postman:use-remote` (the hosted server needs no local runtime). diff --git a/commands/use-remote.md b/commands/use-remote.md new file mode 100644 index 0000000..1a727cc --- /dev/null +++ b/commands/use-remote.md @@ -0,0 +1,57 @@ +--- +description: Switch this plugin's Postman MCP Server to the REMOTE hosted server (https://mcp.postman.com/mcp, full mode). Authenticates via OAuth. +allowed-tools: Bash, Read, Write +--- + +# Use Remote MCP Server + +Point this plugin back at Postman's **remote** hosted MCP Server (`https://mcp.postman.com`, Full mode) instead of the local stdio package. This rewrites the plugin's own `.mcp.json` in place, changing only the transport (local → remote). The hosted server authenticates via OAuth — no API key required. + +This is the plugin's default configuration. Switch to the local package at any time with `/postman:use-local`. + +## Workflow + +### Step 1: Locate this plugin's `.mcp.json` + +The file to rewrite is the `.mcp.json` bundled with this plugin (it lives at the plugin's root, next to `.claude-plugin/`). Find it and show the current content: + +```bash +for f in "$CLAUDE_PLUGIN_ROOT/.mcp.json" "$HOME"/.claude/plugins/*/.mcp.json "$HOME"/.claude/plugins/*/*/.mcp.json; do + [ -f "$f" ] || continue + if grep -q '"postman"' "$f"; then echo "FOUND: $f"; echo "--- current content ---"; cat "$f"; echo; fi +done +``` + +Use the `FOUND:` path as the target file to edit. If nothing is found, stop and ask the user for the path to the installed plugin's `.mcp.json`. + +### Step 2: Overwrite the target `.mcp.json` + +Write exactly this content to the `FOUND:` path. This is the plugin's canonical remote form — Full mode (`https://mcp.postman.com/mcp`) with `X-Source` attribution headers: + +```json +{ + "mcpServers": { + "postman": { + "type": "http", + "url": "https://mcp.postman.com/${POSTMAN_MCP_MODE:-mcp}", + "headers": { + "X-Source": "claude-code-plugin", + "X-Plugin-Version": "1.2.0", + "User-Agent": "postman-claude-code-plugin/1.2.0" + } + } + } +} +``` + +The `${POSTMAN_MCP_MODE:-mcp}` expansion defaults to `/mcp` (Full mode, 100+ tools) and honors a `POSTMAN_MCP_MODE` environment variable if the user wants a lighter toolset (`minimal`, `code`). Full mode is required by commands like `/postman:learn` (its `searchLearningCenter` tool is absent in `minimal` and `code` modes). Keep the `X-Source` / version headers intact so remote traffic stays attributed to this plugin. + +### Step 3: Confirm and restart + +Print the new file content back to the user, confirm the switch (local → remote hosted server), and tell them to **restart Claude Code** for the change to take effect. On first use, run `/postman:setup` to complete the Postman OAuth login (no API key needed). Remind them they can switch to the local package at any time with `/postman:use-local`. + +## Error Handling + +- **`.mcp.json` not found:** Ask the user for the path to the installed plugin's `.mcp.json`, or tell them to reinstall the plugin. +- **Connection fails after switching:** Run `/postman:setup` to (re)authenticate via OAuth against the hosted server. +- **401 Unauthorized:** "Your Postman session was rejected. Run `/postman:setup` to re-authenticate via OAuth."