diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index ad16d86..b98e5cf 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "postman", - "version": "1.1.0", + "version": "1.2.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/.github/scripts/validate-frontmatter.py b/.github/scripts/validate-frontmatter.py index 9c7c87f..37da84d 100755 --- a/.github/scripts/validate-frontmatter.py +++ b/.github/scripts/validate-frontmatter.py @@ -9,7 +9,13 @@ # PyYAML is not guaranteed on all runners, so parse simple YAML manually FRONTMATTER_RE = re.compile(r"^---\s*\n(.*?)\n---", re.DOTALL) -KNOWN_TOOLS = {"Bash", "Read", "Write", "Glob", "Grep", "mcp__postman__*"} +KNOWN_TOOLS = {"Bash", "Read", "Write", "Edit", "Glob", "Grep"} +# Specific Postman MCP tools are preferred over the mcp__postman__* wildcard +MCP_TOOL_RE = re.compile(r"^mcp__postman__[A-Za-z0-9_]+$") + + +def is_known_tool(tool: str) -> bool: + return tool in KNOWN_TOOLS or MCP_TOOL_RE.match(tool) is not None def parse_frontmatter(text: str) -> Optional[dict]: @@ -46,7 +52,7 @@ def validate_commands(root: Path) -> list[str]: if "allowed-tools" in fm and fm["allowed-tools"]: tools = [t.strip() for t in fm["allowed-tools"].split(",")] for tool in tools: - if tool not in KNOWN_TOOLS: + if not is_known_tool(tool): errors.append(f"{f.name}: Unknown tool '{tool}' in allowed-tools") return errors @@ -98,7 +104,7 @@ def validate_agents(root: Path) -> list[str]: if "allowed-tools" in fm and fm["allowed-tools"]: tools = [t.strip() for t in fm["allowed-tools"].split(",")] for tool in tools: - if tool not in KNOWN_TOOLS: + if not is_known_tool(tool): errors.append(f"agents/{f.name}: Unknown tool '{tool}' in allowed-tools") return errors diff --git a/.github/scripts/validate-structure.py b/.github/scripts/validate-structure.py index f9e9e96..ca360b1 100755 --- a/.github/scripts/validate-structure.py +++ b/.github/scripts/validate-structure.py @@ -73,7 +73,7 @@ def main(): errors.append("agents/: Directory not found") # 6. Check for stray markdown files in root (not README, CLAUDE, LICENSE, or examples) - expected_root_md = {"README.md", "CLAUDE.md", "LICENSE"} + expected_root_md = {"README.md", "CLAUDE.md", "LICENSE", "token-optimization-findings.md"} for f in sorted(root.glob("*.md")): if f.name not in expected_root_md: errors.append(f"{f.name}: Unexpected markdown file in repo root") diff --git a/.mcp.json b/.mcp.json index 7a4d6da..bf8ba33 100644 --- a/.mcp.json +++ b/.mcp.json @@ -2,11 +2,11 @@ "mcpServers": { "postman": { "type": "http", - "url": "https://mcp.postman.com/mcp", + "url": "https://mcp.postman.com/${POSTMAN_MCP_MODE:-mcp}", "headers": { "X-Source": "claude-code-plugin", - "X-Plugin-Version": "1.1.0", - "User-Agent": "postman-claude-code-plugin/1.1.0" + "X-Plugin-Version": "1.2.0", + "User-Agent": "postman-claude-code-plugin/1.2.0" } } } diff --git a/CLAUDE.md b/CLAUDE.md index fa8db36..3ac0b64 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -11,18 +11,19 @@ The Postman Plugin for Claude Code — a pure-markdown, configuration-driven plu ``` .claude-plugin/plugin.json # Plugin manifest (name, version, metadata) .mcp.json # MCP server auto-config (Postman MCP at mcp.postman.com) -commands/*.md # 11 slash commands (/postman:) -skills/*/SKILL.md # 8 skills (routing, knowledge, agent-ready APIs, CLI, send-request, generate-spec, run-collection, context) +commands/*.md # 10 slash commands (/postman:) +skills/*/SKILL.md # 7 skills (knowledge, agent-ready APIs, CLI, send-request, generate-spec, run-collection, context) +skills/*/references/*.md # On-demand reference files loaded by skills only when needed agents/readiness-analyzer.md # Sub-agent for API readiness analysis examples/ # Sample output (readiness report) -assets/ # GIFs for README ``` ## How the Plugin Works - Claude Code discovers components via `.claude-plugin/plugin.json` manifest -- `.mcp.json` auto-configures the Postman MCP server, providing `mcp__postman__*` tools (111 tools) -- MCP commands use the cloud Postman MCP Server — requires `POSTMAN_API_KEY` environment variable +- `.mcp.json` auto-configures the Postman MCP server, providing `mcp__postman__*` tools. The server mode is switchable via `POSTMAN_MCP_MODE` (`mcp` full/default, `minimal`, or `code` — the latter two expose fewer tools; `minimal` lacks the `*Context` code-gen tools) +- MCP commands use the cloud Postman MCP Server — authenticate via OAuth in `/postman:setup` or a `POSTMAN_API_KEY` environment variable +- Routing is native: there is no routing skill. Claude matches user intent to commands/skills from their front-matter `description` fields, so descriptions must state when to use the component - CLI commands use the locally installed Postman CLI (`npm install -g postman-cli`) — requires `postman login` - Plugin is loaded with `claude --plugin-dir /path/to/postman-claude-code-plugin` @@ -32,7 +33,9 @@ assets/ # GIFs for README - MCP commands: setup, sync, search, test, mock, docs, security - CLI commands: request, generate-spec, run-collection -**Skills** (`skills/*/SKILL.md`): YAML front matter with `name`, `description`, `user-invocable`. Auto-injected context, not directly invoked. `postman-routing` routes requests to commands; `postman-knowledge` provides MCP tool guidance; `agent-ready-apis` provides readiness criteria; `postman-cli` provides CLI and git sync file structure knowledge; `postman-context` provides API discovery, exploration, and code generation from real API definitions via `postman context` CLI commands. +**Skills** (`skills/*/SKILL.md`): YAML front matter with `name`, `description`, `user-invocable`. Auto-injected context, not directly invoked. `postman-knowledge` provides MCP tool guidance; `agent-ready-apis` provides readiness criteria; `postman-cli` provides CLI and git sync file structure knowledge; `postman-context` provides API discovery, exploration, and code generation from real API definitions. + +Large skills use progressive disclosure: a lean SKILL.md holds the workflow, and detailed rules live in `references/*.md` files inside the skill directory that the skill instructs Claude to Read only at the step that needs them (see `postman-context` and `generate-spec`). Keep new skills under ~6KB and put bulky templates/rules in references. **Agent** (`agents/readiness-analyzer.md`): YAML front matter with `name`, `description`, `model`, `allowed-tools`. Runs as a sub-agent (sonnet model) for deep API readiness analysis (8 pillars, 48 checks). @@ -64,4 +67,5 @@ CLI commands work with Postman's git sync structure: `postman/collections/` (v3 - When adding a new command, follow the existing front matter pattern in `commands/` - When adding a new skill, create `skills//SKILL.md` with proper front matter - The `allowed-tools` field in front matter controls what tools a command/agent can use -- CLI commands need `Bash` in `allowed-tools`; MCP commands need `mcp__postman__*` +- CLI commands need `Bash` in `allowed-tools`; MCP commands list the specific `mcp__postman__` tools they call — never the `mcp__postman__*` wildcard. When a command's workflow gains a new MCP call, add that tool to its `allowed-tools` +- Front-matter `description` fields are injected into every user session — keep them to one or two sentences (what it does + when to use it) diff --git a/README.md b/README.md index 7b73105..d79ea96 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,9 @@ The Postman Plugin provides a single, simple install for Claude Code. It provides full API lifecycle management, and best practices when working with Postman APIs. -

- Postman plugin syncing code -> collection -

- ## What's included: - Commands for setting up the Postman MCP Server (no more manual installs!), working with Collections, Tests, Mock Servers, and generating code and documentation from Collections -- Skills for Postman Routing, API best practices, and API OWASP security reviews +- Skills for API discovery and client code generation, OpenAPI spec generation, Postman CLI workflows, and API best practices - Agent for reviewing API production readiness and providing recommendations based on the Postman API Readiness Guide. ## Installation @@ -32,32 +28,26 @@ claude --plugin-dir /path/to/postman-claude-code-plugin ## Quick Start -1. Set your API key: -```bash -export POSTMAN_API_KEY=PMAK-your-key-here -``` -Add it to your shell profile (`~/.zshrc` or `~/.bashrc`) to persist across sessions. - -2. Start Claude Code with the plugin: +1. Start Claude Code with the plugin: ```bash claude --plugin-dir /path/to/postman-claude-code-plugin ``` -3. Run setup: +2. Run setup: ``` /postman:setup ``` -That's it. The plugin auto-configures the Postman MCP Server, verifies your connection, and lists your workspaces. You're ready to go. +3. Authenticate when prompted — **OAuth (recommended)**, which opens a browser sign-in with no key copying, or an API key: +```bash +export POSTMAN_API_KEY=PMAK-your-key-here +``` +If you use an API key, add it to your shell profile (`~/.zshrc` or `~/.bashrc`) to persist across sessions. Get one at [go.postman.co/settings/me/api-keys](https://go.postman.co/settings/me/api-keys). -Get your API key at [go.postman.co/settings/me/api-keys](https://go.postman.co/settings/me/api-keys). +That's it. The plugin auto-configures the Postman MCP Server, verifies your connection, and lists your workspaces. You're ready to go. ## Commands -

- Postman Plugin generating code from a collection -

- | Command | What It Does | |---------|-------------| | `/postman:setup` | Configure API key, verify connection, select workspace | @@ -71,10 +61,6 @@ Get your API key at [go.postman.co/settings/me/api-keys](https://go.postman.co/s ## What You Can Do -

- Postman Plugin creating a mock server to be used in code to mock an API -

- ### Sync your API to Postman ``` "Sync my OpenAPI spec with Postman" @@ -117,20 +103,16 @@ Get your API key at [go.postman.co/settings/me/api-keys](https://go.postman.co/s → 48 checks across 8 pillars, scored 0-100, prioritized fix recommendations ``` -## Auto-Routing +## Natural Language Routing -You don't need to remember command names. The plugin's routing skill detects your intent and runs the right command: +You don't need to remember command names. Claude matches your intent to the right command or skill natively: -- "Sync my collection" routes to `/postman:sync` -- "Check for vulnerabilities" routes to `/postman:security` +- "Sync my collection" runs `/postman:sync` +- "Check for vulnerabilities" runs `/postman:security` - "Is my API agent-ready?" triggers the readiness analyzer ## API Readiness Analyzer -

- Postman Plugin analyzing your API for AI Readiness -

- The built-in readiness analyzer evaluates APIs for AI agent compatibility across 8 pillars: | Pillar | What It Checks | @@ -149,12 +131,19 @@ The built-in readiness analyzer evaluates APIs for AI agent compatibility across ## Requirements - Claude Code v1.0.33+ -- Postman API key (`POSTMAN_API_KEY` environment variable) +- A Postman account — authenticate via OAuth during `/postman:setup`, or set a `POSTMAN_API_KEY` environment variable - No Python, Node, or other runtime dependencies ## How It Works -The plugin bundles a `.mcp.json` file that auto-configures the [Postman MCP Server](https://github.com/postmanlabs/postman-mcp-server) when installed. All commands communicate with Postman through 111 MCP tools. No scripts, no dependencies, pure MCP. +The plugin bundles a `.mcp.json` file that auto-configures the [Postman MCP Server](https://github.com/postmanlabs/postman-mcp-server) when installed. All commands communicate with Postman through MCP tools. No scripts, no dependencies, pure MCP. + +By default the plugin connects to the full Postman MCP Server (100+ tools). Recent Claude Code versions load MCP tool schemas on demand, so the full server adds little context overhead. If you're on an older client or want a lighter session, set `POSTMAN_MCP_MODE` before starting Claude Code to pick a smaller server mode: + +```bash +export POSTMAN_MCP_MODE=minimal # ~42 CRUD tools; code-generation (context) tools unavailable +export POSTMAN_MCP_MODE=code # ~24 read-only tools for API discovery and client code generation +``` ## License diff --git a/agents/readiness-analyzer.md b/agents/readiness-analyzer.md index fd81cf9..637ad0f 100644 --- a/agents/readiness-analyzer.md +++ b/agents/readiness-analyzer.md @@ -1,8 +1,8 @@ --- name: API Readiness Analyzer -description: "Analyze any API for AI agent compatibility. Scans OpenAPI specs across 8 pillars (48 checks), scores agent-readiness, and provides fix recommendations. Triggers on: 'Is my API agent-ready?', 'Scan my API', 'Analyze my OpenAPI spec', 'What\\'s wrong with my API for AI agents?', 'How agent-friendly is my API?'." +description: Analyze any API or OpenAPI spec for AI agent compatibility — 48 checks across 8 pillars, with scoring and fix recommendations. Use when the user asks whether an API is agent-ready or wants it scanned, scored, or improved for AI agents. model: sonnet -allowed-tools: Read, Glob, Grep, Bash, mcp__postman__* +allowed-tools: Read, Edit, Write, Glob, Grep, Bash, mcp__postman__getWorkspaces, mcp__postman__getAllSpecs, mcp__postman__getSpecDefinition, mcp__postman__createSpec, mcp__postman__generateCollection, mcp__postman__getAsyncSpecTaskStatus, mcp__postman__getGeneratedCollectionSpecs, mcp__postman__createEnvironment, mcp__postman__createMock, mcp__postman__runCollection, mcp__postman__publishDocumentation --- # API Readiness Analyzer diff --git a/assets/postman-plugin-api-ai-check.gif b/assets/postman-plugin-api-ai-check.gif deleted file mode 100644 index db13336..0000000 Binary files a/assets/postman-plugin-api-ai-check.gif and /dev/null differ diff --git a/assets/postman-plugin-codegen.gif b/assets/postman-plugin-codegen.gif deleted file mode 100644 index ef5bab5..0000000 Binary files a/assets/postman-plugin-codegen.gif and /dev/null differ diff --git a/assets/postman-plugin-mock-server.gif b/assets/postman-plugin-mock-server.gif deleted file mode 100644 index c69a511..0000000 Binary files a/assets/postman-plugin-mock-server.gif and /dev/null differ diff --git a/assets/postman-plugin-sync.gif b/assets/postman-plugin-sync.gif deleted file mode 100644 index de27c85..0000000 Binary files a/assets/postman-plugin-sync.gif and /dev/null differ diff --git a/commands/docs.md b/commands/docs.md index c856c30..7c417f0 100644 --- a/commands/docs.md +++ b/commands/docs.md @@ -1,6 +1,6 @@ --- description: Generate, improve, and publish API documentation from Postman collections. -allowed-tools: Read, Glob, Grep, mcp__postman__* +allowed-tools: Read, Write, Glob, Grep, mcp__postman__getWorkspaces, mcp__postman__getAllSpecs, mcp__postman__getSpecDefinition, mcp__postman__getCollections, mcp__postman__getCollection, mcp__postman__updateCollectionRequest, mcp__postman__publishDocumentation, mcp__postman__unpublishDocumentation, mcp__postman__syncCollectionWithSpec, mcp__postman__syncSpecWithCollection, mcp__postman__getCollectionUpdatesTasks --- # API Documentation @@ -76,7 +76,7 @@ Ask the user which output they want: ### Step 5: Sync Spec and Collection If both a spec and collection exist, keep them in sync: -- Call `syncCollectionWithSpec` to update collection from spec. **Async (HTTP 202).** Poll `getCollectionUpdatesTasks` for completion. Only supports OpenAPI 3.0. +- Call `syncCollectionWithSpec` to update collection from spec. **Async (HTTP 202).** Poll `getCollectionUpdatesTasks` for completion with increasing waits between polls. Only supports OpenAPI 3.0. - Or call `syncSpecWithCollection` to update spec from collection changes. ## Error Handling diff --git a/commands/mock.md b/commands/mock.md index 7b86456..83cf02e 100644 --- a/commands/mock.md +++ b/commands/mock.md @@ -1,6 +1,6 @@ --- description: Create Postman mock servers for frontend development. Generates missing examples, provides integration config. -allowed-tools: Bash, Read, Write, Glob, Grep, mcp__postman__* +allowed-tools: Bash, Read, Write, Glob, Grep, mcp__postman__getWorkspaces, mcp__postman__getCollections, mcp__postman__getCollection, mcp__postman__getCollectionRequest, mcp__postman__createCollectionResponse, mcp__postman__createSpec, mcp__postman__generateCollection, mcp__postman__getGeneratedCollectionSpecs, mcp__postman__getSpecCollections, mcp__postman__getAsyncSpecTaskStatus, mcp__postman__getMocks, mcp__postman__getMock, mcp__postman__createMock, mcp__postman__publishMock, mcp__postman__unpublishMock --- # Create Mock Servers @@ -25,7 +25,7 @@ Call `getWorkspaces` to get the user's workspace ID. If multiple workspaces exis - Find OpenAPI spec in the project - Import it first: 1. Call `createSpec` with `workspaceId`, `name`, `type`, and `files` - 2. Call `generateCollection`. **Async (HTTP 202).** Poll `getGeneratedCollectionSpecs` or `getSpecCollections` for completion. Note: `getAsyncSpecTaskStatus` may return 403 on some plans. + 2. Call `generateCollection`. **Async (HTTP 202).** Poll `getGeneratedCollectionSpecs` or `getSpecCollections` for completion, with increasing waits between polls (2s, 4s, 8s). Note: `getAsyncSpecTaskStatus` may return 403 on some plans. ### Step 2: Check for Examples diff --git a/commands/search.md b/commands/search.md index f27f872..6ae19f2 100644 --- a/commands/search.md +++ b/commands/search.md @@ -1,6 +1,6 @@ --- description: Discover APIs across your Postman workspaces. Ask natural language questions about available endpoints and capabilities. -allowed-tools: Read, Glob, Grep, mcp__postman__* +allowed-tools: Read, Glob, Grep, mcp__postman__searchPostmanElementsInPrivateNetwork, mcp__postman__searchPostmanElementsInPublicNetwork, mcp__postman__getWorkspaces, mcp__postman__getCollections, mcp__postman__getTaggedEntities, mcp__postman__getCollection, mcp__postman__getCollectionRequest, mcp__postman__getCollectionResponse, mcp__postman__getSpecDefinition --- # Discover APIs diff --git a/commands/security.md b/commands/security.md index 273c9e3..f3ad3a2 100644 --- a/commands/security.md +++ b/commands/security.md @@ -1,6 +1,6 @@ --- description: Security audit your APIs against OWASP API Top 10. Finds vulnerabilities and provides remediation guidance. -allowed-tools: Read, Glob, Grep, mcp__postman__* +allowed-tools: Read, Edit, Write, Glob, Grep, mcp__postman__getWorkspaces, mcp__postman__getAllSpecs, mcp__postman__getSpecDefinition, mcp__postman__getCollections, mcp__postman__getCollection, mcp__postman__getEnvironment, mcp__postman__putEnvironment, mcp__postman__updateCollectionRequest, mcp__postman__updateCollectionResponse --- # API Security Audit diff --git a/commands/setup.md b/commands/setup.md index f628f79..0d9fe24 100644 --- a/commands/setup.md +++ b/commands/setup.md @@ -1,6 +1,6 @@ --- description: Set up Postman MCP Server. Authenticate via OAuth or API key, verify connection, select workspace. -allowed-tools: mcp__postman__* +allowed-tools: mcp__postman__authenticate, mcp__postman__complete_authentication, mcp__postman__getAuthenticatedUser, mcp__postman__getWorkspaces, mcp__postman__getCollections, mcp__postman__getAllSpecs --- # First-Run Configuration diff --git a/commands/sync.md b/commands/sync.md index c3585f7..894110e 100644 --- a/commands/sync.md +++ b/commands/sync.md @@ -1,6 +1,6 @@ --- description: Sync Postman collections with your API code. Create collections from specs, push updates, keep everything in sync. -allowed-tools: Bash, Read, Write, Glob, Grep, mcp__postman__* +allowed-tools: Bash, Read, Write, Glob, Grep, mcp__postman__getWorkspaces, mcp__postman__getCollections, mcp__postman__getCollection, mcp__postman__createSpec, mcp__postman__updateSpecFile, mcp__postman__generateCollection, mcp__postman__getAsyncSpecTaskStatus, mcp__postman__getGeneratedCollectionSpecs, mcp__postman__syncCollectionWithSpec, mcp__postman__syncSpecWithCollection, mcp__postman__getCollectionUpdatesTasks, mcp__postman__createEnvironment, mcp__postman__createCollectionRequest, mcp__postman__updateCollectionRequest, mcp__postman__createCollectionFolder, mcp__postman__createCollectionResponse --- # Sync Collections @@ -38,7 +38,7 @@ Call `getWorkspaces` to get the user's workspace ID. If multiple workspaces exis - `name`: from the spec's `info.title` - `type`: one of `OPENAPI:2.0`, `OPENAPI:3.0`, `OPENAPI:3.1`, `ASYNCAPI:2.0` - `files`: array of `{path, content}` objects -3. Call `generateCollection` from the spec. **This is async (HTTP 202).** Poll `getAsyncSpecTaskStatus` or `getGeneratedCollectionSpecs` until complete. +3. Call `generateCollection` from the spec. **This is async (HTTP 202).** Poll `getAsyncSpecTaskStatus` or `getGeneratedCollectionSpecs` until complete, with increasing waits between polls (2s, 4s, 8s). Don't narrate intermediate poll results — report only the final outcome. 4. Call `createEnvironment` with variables extracted from the spec: - `base_url` from `servers[0].url` - Auth variables from `securitySchemes` (mark as `secret`) @@ -48,7 +48,7 @@ Call `getWorkspaces` to get the user's workspace ID. If multiple workspaces exis **Spec to Collection (most common):** 1. Call `createSpec` or `updateSpecFile` with local spec content -2. Call `syncCollectionWithSpec` to update the collection. **Async (HTTP 202).** Poll `getCollectionUpdatesTasks` for completion. +2. Call `syncCollectionWithSpec` to update the collection. **Async (HTTP 202).** Poll `getCollectionUpdatesTasks` for completion with increasing waits between polls. 3. **Note:** `syncCollectionWithSpec` only supports OpenAPI 3.0. For Swagger 2.0 or OpenAPI 3.1, use `updateSpecFile` and regenerate the collection. 4. Report what changed diff --git a/commands/test.md b/commands/test.md index 19c40ee..e907647 100644 --- a/commands/test.md +++ b/commands/test.md @@ -1,6 +1,6 @@ --- description: Run Postman collection tests, analyze results, diagnose failures, and suggest fixes. -allowed-tools: Bash, Read, Write, Glob, Grep, mcp__postman__* +allowed-tools: Bash, Read, Write, Glob, Grep, mcp__postman__getWorkspaces, mcp__postman__getCollections, mcp__postman__getCollection, mcp__postman__runCollection, mcp__postman__getEnvironments, mcp__postman__getCollectionRequest, mcp__postman__getCollectionResponse, mcp__postman__updateCollectionRequest, mcp__postman__updateCollectionResponse --- # Run Collection Tests diff --git a/skills/generate-spec/SKILL.md b/skills/generate-spec/SKILL.md index 74cb4c5..8ce276f 100644 --- a/skills/generate-spec/SKILL.md +++ b/skills/generate-spec/SKILL.md @@ -1,18 +1,15 @@ --- name: generate-spec -description: Generate or update an OpenAPI specification from code - use when user says "generate spec", "create spec", "create openapi spec", "update spec", "generate API documentation", "create API definition", "write openapi", "document my API", "create swagger", or wants to create/update an API specification from their codebase +description: Generate or update an OpenAPI 3.0 spec from code. Use when the user wants to create, update, or write an OpenAPI/Swagger spec, API definition, or API documentation from their codebase. --- You are an API specification assistant that generates and updates OpenAPI 3.0 specifications by analyzing the user's codebase. ## When to Use This Skill -Trigger this skill when: -- User asks to "generate a spec" or "create an OpenAPI spec" -- User wants to "document my API" or "create API documentation" -- User says "update the spec" or "sync spec with code" -- User asks to "create a swagger file" or "write an API definition" -- User wants to generate an API spec from their existing routes/endpoints +Use this skill when the user wants to generate, create, or update an OpenAPI/Swagger spec or API definition from their existing routes and endpoints. + +A reference file in this skill's directory, `references/spec-template.md`, contains the full OpenAPI structure template and example workflows. Read it with the Read tool when you reach Step 3. --- @@ -88,91 +85,7 @@ ls openapi.yaml openapi.yml openapi.json swagger.yaml swagger.yml swagger.json a ## Step 3: Generate the OpenAPI 3.0 Spec -Build a valid OpenAPI 3.0 specification in YAML format. Follow this structure: - -```yaml -openapi: 3.0.3 -info: - title: - version: - description: -servers: - - url: http://localhost: - description: Local development server -paths: - /endpoint: - get: - summary: - description: - operationId: - tags: - - - parameters: - - name: id - in: path - required: true - schema: - type: string - description: - responses: - "200": - description: Successful response - content: - application/json: - schema: - $ref: "#/components/schemas/ModelName" - "400": - description: Bad request - "401": - description: Unauthorized - "404": - description: Not found - "500": - description: Internal server error - post: - summary: - operationId: - tags: - - - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/CreateModel" - responses: - "201": - description: Created successfully - content: - application/json: - schema: - $ref: "#/components/schemas/ModelName" -components: - schemas: - ModelName: - type: object - required: - - id - - name - properties: - id: - type: string - description: Unique identifier - name: - type: string - description: Display name - securitySchemes: - bearerAuth: - type: http - scheme: bearer - bearerFormat: JWT - apiKey: - type: apiKey - in: header - name: X-API-Key -``` - -### Key rules for generating the spec: +Read `references/spec-template.md` for the full YAML structure template, then build a valid OpenAPI 3.0 specification in YAML format following these rules: 1. **Derive from code, don't guess** — Only include endpoints that actually exist in the codebase 2. **Extract real schemas** — Use model definitions, TypeScript types, Pydantic models, or struct definitions to build component schemas @@ -236,77 +149,7 @@ If Postman CLI is not installed, tell the user: "Install Postman CLI (`npm insta ## Step 6: Report Results -**New spec created:** -``` -Created OpenAPI 3.0 spec at postman/specs/openapi.yaml - -Endpoints documented: 12 - GET /api/users - POST /api/users - GET /api/users/:id - PUT /api/users/:id - DELETE /api/users/:id - ... - -Schemas defined: 5 - User, CreateUser, UpdateUser, ErrorResponse, PaginatedResponse - -Validation: ✓ No errors -``` - -**Existing spec updated:** -``` -Updated OpenAPI spec at postman/specs/openapi.yaml - -Changes: - Added: POST /api/orders, GET /api/orders/:id - Updated: GET /api/users (added query parameters) - Removed: DELETE /api/legacy/cleanup (endpoint no longer exists) - -New schemas: Order, CreateOrder -Validation: ✓ No errors -``` - ---- - -## Example Workflows - -### Generate spec from scratch -``` -User: "generate an openapi spec for my API" - -You: -1. Scan project for route definitions -2. Read route files and extract endpoints -3. Read models/types for schemas -4. Generate openapi.yaml -5. Validate with postman spec lint -6. Report: "Created spec with 12 endpoints and 5 schemas" -``` - -### Update spec after code changes -``` -User: "update the spec, I added new endpoints" - -You: -1. Read existing spec -2. Scan code for all current endpoints -3. Diff against existing spec -4. Add new endpoints, update changed ones -5. Validate -6. Report: "Added 2 new endpoints, updated 1" -``` - -### Generate spec for specific routes -``` -User: "create a spec for the user routes" - -You: -1. Find user-related route files -2. Extract only user endpoints -3. Generate focused spec -4. Validate and report -``` +Report concisely what was created or changed: the file path, endpoints documented (count and list), schemas defined, changes from the previous spec (added/updated/removed) when updating, and the validation result. --- diff --git a/skills/generate-spec/references/spec-template.md b/skills/generate-spec/references/spec-template.md new file mode 100644 index 0000000..3139341 --- /dev/null +++ b/skills/generate-spec/references/spec-template.md @@ -0,0 +1,118 @@ +# OpenAPI 3.0 Spec Structure Template + +Use this structure when generating a spec. Fill every placeholder from real code — never fabricate endpoints or schemas. + +```yaml +openapi: 3.0.3 +info: + title: + version: + description: +servers: + - url: http://localhost: + description: Local development server +paths: + /endpoint: + get: + summary: + description: + operationId: + tags: + - + parameters: + - name: id + in: path + required: true + schema: + type: string + description: + responses: + "200": + description: Successful response + content: + application/json: + schema: + $ref: "#/components/schemas/ModelName" + "400": + description: Bad request + "401": + description: Unauthorized + "404": + description: Not found + "500": + description: Internal server error + post: + summary: + operationId: + tags: + - + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/CreateModel" + responses: + "201": + description: Created successfully + content: + application/json: + schema: + $ref: "#/components/schemas/ModelName" +components: + schemas: + ModelName: + type: object + required: + - id + - name + properties: + id: + type: string + description: Unique identifier + name: + type: string + description: Display name + securitySchemes: + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + apiKey: + type: apiKey + in: header + name: X-API-Key +``` + +## Example Workflows + +### Generate spec from scratch + +User: "generate an openapi spec for my API" + +1. Scan project for route definitions +2. Read route files and extract endpoints +3. Read models/types for schemas +4. Generate openapi.yaml +5. Validate with postman spec lint +6. Report: "Created spec with 12 endpoints and 5 schemas" + +### Update spec after code changes + +User: "update the spec, I added new endpoints" + +1. Read existing spec +2. Scan code for all current endpoints +3. Diff against existing spec +4. Add new endpoints, update changed ones +5. Validate +6. Report: "Added 2 new endpoints, updated 1" + +### Generate spec for specific routes + +User: "create a spec for the user routes" + +1. Find user-related route files +2. Extract only user endpoints +3. Generate focused spec +4. Validate and report diff --git a/skills/postman-context/SKILL.md b/skills/postman-context/SKILL.md index e16a040..694026f 100644 --- a/skills/postman-context/SKILL.md +++ b/skills/postman-context/SKILL.md @@ -1,22 +1,13 @@ --- name: postman-context -description: Discover, explore, integrate, and generate code from Postman APIs - use when user says "find an API", "search for API", "install API", "integrate with API", "generate client code", "write API client", "explore collection", "what APIs are available", or when writing any service client, API wrapper, or integration code from a Postman collection — even if the collection was already explored via MCP tools +description: Discover, explore, install, and generate client code from APIs in Postman. Use when the user wants to find or integrate an API, explore a collection, or generate or maintain API client code — required before generating code from any Postman collection, even one already explored via MCP tools. --- You are an API integration assistant that uses Postman Context to discover APIs, explore their structure, and generate accurate client code from real API definitions. ## When to Use This Skill -Trigger this skill when: -- User asks to "find an API" or "give an API for " -- User wants to "integrate with" or "connect to" an API -- User says "install the API" or "add the API" -- User wants to "generate client code", "write an API client", or create a service wrapper -- User asks "what APIs are available" or "what endpoints does this API have" -- User wants to explore a Postman collection's structure -- User has explored a collection (via MCP or otherwise) and is ready to generate code from it -- User is about to write HTTP client code for endpoints that exist in a Postman collection -- User asks to maintain, update, or remove installed API integrations +Use this skill when the user wants to find, install, or integrate an API; generate client code or a service wrapper; explore a Postman collection's structure; or list, update, or remove installed API integrations. **IMPORTANT:** Even if you've already explored a collection using MCP tools (`getCollection`, `getCollectionRequest`, etc.), you MUST still use this skill before generating client code. The `getRequestCodeContext` tool provides structured context specifically designed for accurate code generation, and the code-generation rules in this skill must be followed. @@ -25,6 +16,13 @@ Trigger this skill when: - User wants to run collection tests (use `run-collection`) - User wants to generate an OpenAPI spec from their own code (use `generate-spec`) +## Reference Files + +Detailed rules live in separate files inside this skill's directory. Read them with the Read tool only when you reach the step that needs them: + +- `references/code-generation.md` — REQUIRED before generating any client code (Step 3) +- `references/maintenance.md` — REQUIRED before listing, updating, or removing installed requests (Step 4) + --- ## Prerequisites @@ -61,14 +59,7 @@ The generic tools (`getCollection`, `getCollectionRequest`, etc.) are for CRUD o ## How Users Start -Users don't typically start by thinking about collections and request IDs. They start with intent: - -- **"Build me a dashboard that shows recent Payvance chargebacks"** — They know what they want to build. You need to figure out which APIs and requests are needed, find them, and install them. -- **"Find me a good email API"** — They have a need but haven't picked an API yet. Search, explore, and help them choose. -- **"Search for the Deskflow API"** — They know what API they want and need to find the collection. -- **"What requests do we have installed?"** — They're managing existing integrations. -- **"Are my API integrations up to date?"** — They want to check for upstream changes and regenerate outdated code. -- **"Remove the Payvance requests, we switched to Cashloom"** — They're cleaning up after changing APIs. +Users don't typically start by thinking about collections and request IDs. They start with intent: "build me a dashboard that shows recent chargebacks" (figure out which APIs and requests are needed), "find me a good email API" (search, explore, help them choose), "what requests do we have installed?" or "are my integrations up to date?" (manage existing integrations). Meet the user where they are. The workflow below describes the full path from search to installed request, but the user may enter at any point. @@ -78,33 +69,15 @@ Meet the user where they are. The workflow below describes the full path from se ### Step 1: Find the API -There are two paths depending on whether the API is public or internal. - -**Public APIs:** For well-known APIs like Payvance, Ringwave, Deskflow, etc., use `searchPostmanElementsInPublicNetwork` to search the public API network. Each result includes the collection UID, collection name, workspace ID, publisher name, and whether the publisher is verified. When presenting results, include Postman links (`https://go.postman.co/collection/`) so the user can explore in Postman if they want. +**Public APIs:** For well-known third-party APIs, use `searchPostmanElementsInPublicNetwork` to search the public API network. Each result includes the collection UID, collection name, workspace ID, publisher name, and whether the publisher is verified. When presenting results, include Postman links (`https://go.postman.co/collection/`) so the user can explore in Postman if they want. -**Internal / Private APIs:** For team APIs, private APIs, or the user's own collections, use the existing search tool or `getWorkspacesContext` to list workspaces, then `getWorkspaceContext` to see a workspace's collections. Key patterns for filtering: +**Internal / Private APIs:** For team APIs, private APIs, or the user's own collections, use the existing search tool or `getWorkspacesContext` to list workspaces, then `getWorkspaceContext` to see a workspace's collections. If the user says "my" (e.g. "my APIs", "my workspaces"), filter to personal workspaces only — this dramatically reduces noise when the team has many workspaces. -- If the user says "my" (e.g. "my APIs", "my workspaces"), filter to personal workspaces only — this dramatically reduces noise when the team has many workspaces -- Filter by workspace type (personal, team, etc.) as appropriate - -**Choosing and comparing APIs:** When the user expresses a need like "I need an email API" or "we need to pick a payment provider," don't just search — help them evaluate. Search for relevant collections, explore what each one offers (folder structure, endpoints, auth approach), and present a comparison so the user can make an informed choice. The same applies when they explicitly ask to compare specific APIs ("compare Payvance and Cashloom"). Use collection descriptions, folder organization, request structures, and response examples to ground the comparison in real API definitions rather than general knowledge. - ---- +**Choosing and comparing APIs:** When the user expresses a need like "I need an email API," don't just search — help them evaluate. Search for relevant collections, explore what each one offers (folder structure, endpoints, auth approach), and present a comparison grounded in real API definitions rather than general knowledge. ### Step 2: Explore the Collection -Once you've identified one or more collections that match the user's intent, explore their structure using the context tools: - -- `getCollectionContext` — Get the collection tree (folders, requests, metadata) -- `getRequestContext` — Get a specific request's full definition -- `getFolderContext` — Get a folder's contents -- `getResponseContext` — Get a saved response example -- `getWorkspaceContext` — Get workspace details -- `getEnvironmentContext` — Get environment variables - -Drill into specific requests or folders as needed. Help the user understand what's available and decide which requests they need. Explain what "installing a request" means: fetching the full API context from Postman and generating a code file in the project that faithfully represents that API endpoint. - ---- +Once you've identified one or more collections that match the user's intent, explore their structure using the context tools from the table above. Drill into specific requests or folders as needed — fetch only what's relevant rather than dumping entire collections. Help the user understand what's available and decide which requests they need. Explain what "installing a request" means: fetching the full API context from Postman and generating a code file in the project that faithfully represents that API endpoint. ### Step 3: Install Requests (Generate Code) @@ -112,13 +85,11 @@ Drill into specific requests or folders as needed. Help the user understand what For each request the user wants to install, use `getRequestCodeContext` to fetch the full context. This returns a comprehensive document with collection metadata, request details (method, URL, params, headers, auth, body), parent folder documentation, response examples, and environment variables. No code generation can proceed without it. -Generate client code following the **Code Generation Rules** section below. Once a request's code has been generated, consider it "installed." - ---- +**Read `references/code-generation.md` now** and generate client code following its rules exactly. Once a request's code has been generated, consider it "installed." ### Step 4: Maintain Installed Requests -Follow the **API Maintenance Rules** section below to help users keep their integrations current. +**Read `references/maintenance.md`** and follow its rules to list installed requests, check for upstream changes, find unused requests, and remove installed requests. --- @@ -129,169 +100,7 @@ Any collection or request can be linked to directly using its UID: - **Collection:** `https://go.postman.co/collection/` - **Request:** `https://go.postman.co/request/` -When the user asks for a link, provide it. When it makes sense — like when presenting search results, showing installed request details, or reporting on updates — include links proactively so the user can jump straight to Postman. - ---- - -## Code Generation Rules - -### Key Principle - -The generated request file must be a faithful representation of the Postman request. Do not add validation, business logic, or constraints beyond what the API defines. That logic belongs in calling code at a higher level. - -### Match the Project - -Before generating, analyze the target project. Follow this priority: - -1. **What the project already does.** Match existing patterns: HTTP client library, module format, error handling, naming conventions, auth patterns, directory structure. If the project uses `axios`, use `axios`. -2. **What is idiomatic for the language/framework.** If no existing pattern exists, use the standard or most common approach. -3. **Sensible defaults.** If neither applies, make a reasonable choice. - -Only deviate from project patterns if the user explicitly asks. - -### File Placement - -1. Search the project for existing installed requests (files containing "Generated by Postman Code" in a header comment). If found, follow the same directory pattern. -2. If no existing installed requests, decide where to place files: - -**Find the root directory.** Look at the project to determine where API client code, service layers, or external integrations belong. Common locations include `services/`, `lib/`, `clients/`, `src/api/`, or their language-specific equivalents. Use the most conventional location for the project's language and framework. Only if no pattern exists, choose a sensible default. - -**Use the collection name as the directory name.** Slugify the collection name for the directory — e.g. a collection called "Stripe API" becomes `stripe-api/`. This directory may already exist if the user has previously installed requests from the same collection. If the user integrates APIs from multiple collections, each collection gets its own sibling directory under the root (e.g. `services/stripe-api/`, `services/sendgrid-api/`). - -**Aim to preserve the collection's folder structure as directories.** Folders in the Postman collection become subdirectories inside the collection directory, and each request becomes a file. Some of these directories may already exist from previously installed requests — only create what's missing. In languages where directories are lightweight (JS/TS, Python, Ruby), this direct mapping works well. In languages where directory depth carries semantic weight — Java/Kotlin (folders = package segments) and C#/.NET (folders = namespace segments) — prefer flatter structures, e.g. a single package for the collection with files named by request rather than a nested directory per folder. - -**Normalize names for the filesystem.** Convert Postman object names to safe directory and file names. In most languages, lowercase and replace non-alphanumeric runs with `-` (e.g. "Stripe API" becomes `stripe-api`). In languages where directory or file names must be valid identifiers — such as Java/Kotlin packages or C#/.NET namespaces — use the language's naming convention instead (e.g. `stripeapi` or `stripe_api`). If two sibling items resolve to the same name, append `-1`, `-2`, etc. (or `_1`, `_2` where hyphens aren't valid). - -### Required File Header - -Every installed request file MUST start with a header comment (in the language's comment syntax). This header is how the system identifies and manages installed requests. - -Required fields: - -- The phrase "Generated by Postman Code" (used for file discovery) -- Collection name and Collection UID -- Request path (folder hierarchy > request name) and Request UID -- Request modified-at timestamp (for update detection) - -Template: - -``` -Generated by Postman Code - -Collection: -Collection UID: - -Request: -Request UID: -Request modified at: -``` - -### Variables File - -If the collection has collection-level variables or the workspace has environments, generate a variables file at the root of the collection directory. - -The purpose of this file is to centralize variable values so the caller can select an environment and pass resolved values to client functions. Structure it as a mapping with: - -- A `collection` key for collection-level variables -- A key for each environment, using the exact environment name from Postman (do not normalize names) - -Use the language's idiomatic construct for a string-keyed mapping — an exported object in JS/TS, a dictionary in Python, a `Map` or similar in Java/C#, a map in Go, etc. Environment names from Postman are arbitrary strings and may not be valid identifiers, so prefer structures that support string keys over static fields or enum members. - -Example (TypeScript): - -```typescript -export const variables = { - collection: { - apiVersion: "v2", - }, - Production: { - baseUrl: "https://api.example.com", - apiKey: "", - }, - Staging: { - baseUrl: "https://api-staging.example.com", - apiKey: "", - }, -}; -``` - -The caller of the generated client is responsible for selecting an environment, merging collection and environment variables, binding secrets, and passing the result to client functions. Don't do that work here. - -### Function Structure - -Generate a single exported function per API endpoint: - -- Accept all dynamic values as explicit parameters (base URL, path variables, query params, body data, auth credentials) -- Do not hardcode variable values — the caller passes them in -- Replace Postman `{{variable}}` placeholders with function parameters -- Accept base URL and URL-related variables as function parameters -- Encode path parameters and query parameters properly -- Build the complete URL from base URL + path - -### Authentication - -Implement the auth scheme from the context document (request-level, folder-level, or collection-level inheritance): - -- Accept credentials as function parameters — never hardcode them -- Support the auth type as documented (API key, Bearer token, Basic auth, etc.) - -### Response Handling - -- Parse the response payload -- If the context includes response examples, add explicit error handling for each documented status code (e.g., if the request has a 404 example, include specific 404 handling) -- Generate typed definitions for request bodies, parameters, and response shapes. Prefer the language's strongest available typing mechanism (e.g., TypeScript interfaces, JSDoc `@typedef` in JavaScript, Python TypedDicts or dataclasses, Go structs, Ruby Structs, PHP typed classes). Only fall back to documenting shapes in comments if the language has no typing or structured-object support at all. -- Follow project conventions for error handling patterns (logging, exception classes, error codes) -- Return or throw errors with meaningful context - -### Documentation - -- Add standard docstrings in the language's convention (JSDoc/TSDoc, Python docstrings, etc.) -- Include the request description from the context document if present -- Document all parameters, return types, and possible errors - -### Extracting Shared Code - -After generating multiple client files for a collection, consolidate duplicated types, auth helpers, and utility functions so they are defined once. - -- Identify duplicated code across clients in the same collection -- Extract shared code and colocate it with the collection's client files using whatever mechanism is idiomatic for the language — a `shared/` subdirectory, a sibling module, a `common` subpackage, unexported helpers in the same package, etc. -- Keep shared code scoped to a single collection by default — only share across collections if the user explicitly asks - -### Quality Verification - -Ensure generated code is lintable, production-ready, type-safe in typed languages, and follows security best practices (no hardcoded secrets, proper input validation). - ---- - -## API Maintenance Rules - -Installed requests include metadata linking them back to their source Postman collection and request. Use these rules to help users keep their integrations current. - -### Listing Installed Requests - -When the user wants to see what's installed, search the project for files containing "Generated by Postman Code" in a comment within the first 15 lines. Parse each file's header to extract: - -- Collection name and Collection UID -- Request path and Request UID -- Request modified-at timestamp - -Present a table showing local file path (relative to project root), collection name, request path, and last modified timestamp. - -### Checking for Updates - -When the user wants to check for API changes, scan for installed requests as above, then for each one use `getRequestContext` to fetch the current request details. Compare the updated-at timestamp from the response to the `Request modified at` timestamp in the file header. Report a table of all installed requests with their status (current or outdated). For any outdated requests, ask the user if they want to regenerate. For confirmed updates, use `getRequestCodeContext` to re-fetch context and regenerate the file in place, matching the existing code style and updating the header timestamp. - -### Finding Unused Requests - -When the user wants to clean up, scan for installed requests, then for each one search the rest of the project for imports, requires, or other references to that file (by module path, relative path, or exported function name). Report any requests with zero references. Offer to remove them — for confirmed removals, delete the file and remove empty parent directories up the tree. - -### Removing Installed Requests - -When the user wants to remove a specific request, identify the file by path, request name, or request UID. If ambiguous, list installed requests first and ask which one. Then: - -1. Delete the request file. -2. Remove empty parent directories up the tree until reaching one with contents. -3. Search the project for imports or requires referencing the deleted file. Warn the user about any broken references so they can update their code. +When the user asks for a link, provide it. When presenting search results, installed request details, or update reports, include links proactively so the user can jump straight to Postman. --- diff --git a/skills/postman-context/references/code-generation.md b/skills/postman-context/references/code-generation.md new file mode 100644 index 0000000..793caf1 --- /dev/null +++ b/skills/postman-context/references/code-generation.md @@ -0,0 +1,129 @@ +# Code Generation Rules + +Read this file in full before generating any client code from a Postman request. + +## Key Principle + +The generated request file must be a faithful representation of the Postman request. Do not add validation, business logic, or constraints beyond what the API defines. That logic belongs in calling code at a higher level. + +## Match the Project + +Before generating, analyze the target project. Follow this priority: + +1. **What the project already does.** Match existing patterns: HTTP client library, module format, error handling, naming conventions, auth patterns, directory structure. If the project uses `axios`, use `axios`. +2. **What is idiomatic for the language/framework.** If no existing pattern exists, use the standard or most common approach. +3. **Sensible defaults.** If neither applies, make a reasonable choice. + +Only deviate from project patterns if the user explicitly asks. + +## File Placement + +1. Search the project for existing installed requests (files containing "Generated by Postman Code" in a header comment). If found, follow the same directory pattern. +2. If no existing installed requests, decide where to place files: + +**Find the root directory.** Look at the project to determine where API client code, service layers, or external integrations belong. Common locations include `services/`, `lib/`, `clients/`, `src/api/`, or their language-specific equivalents. Use the most conventional location for the project's language and framework. Only if no pattern exists, choose a sensible default. + +**Use the collection name as the directory name.** Slugify the collection name for the directory — e.g. a collection called "Stripe API" becomes `stripe-api/`. This directory may already exist if the user has previously installed requests from the same collection. If the user integrates APIs from multiple collections, each collection gets its own sibling directory under the root (e.g. `services/stripe-api/`, `services/sendgrid-api/`). + +**Aim to preserve the collection's folder structure as directories.** Folders in the Postman collection become subdirectories inside the collection directory, and each request becomes a file. Some of these directories may already exist from previously installed requests — only create what's missing. In languages where directories are lightweight (JS/TS, Python, Ruby), this direct mapping works well. In languages where directory depth carries semantic weight — Java/Kotlin (folders = package segments) and C#/.NET (folders = namespace segments) — prefer flatter structures, e.g. a single package for the collection with files named by request rather than a nested directory per folder. + +**Normalize names for the filesystem.** Convert Postman object names to safe directory and file names. In most languages, lowercase and replace non-alphanumeric runs with `-` (e.g. "Stripe API" becomes `stripe-api`). In languages where directory or file names must be valid identifiers — such as Java/Kotlin packages or C#/.NET namespaces — use the language's naming convention instead (e.g. `stripeapi` or `stripe_api`). If two sibling items resolve to the same name, append `-1`, `-2`, etc. (or `_1`, `_2` where hyphens aren't valid). + +## Required File Header + +Every installed request file MUST start with a header comment (in the language's comment syntax). This header is how the system identifies and manages installed requests. + +Required fields: + +- The phrase "Generated by Postman Code" (used for file discovery) +- Collection name and Collection UID +- Request path (folder hierarchy > request name) and Request UID +- Request modified-at timestamp (for update detection) + +Template: + +``` +Generated by Postman Code + +Collection: +Collection UID: + +Request: +Request UID: +Request modified at: +``` + +## Variables File + +If the collection has collection-level variables or the workspace has environments, generate a variables file at the root of the collection directory. + +The purpose of this file is to centralize variable values so the caller can select an environment and pass resolved values to client functions. Structure it as a mapping with: + +- A `collection` key for collection-level variables +- A key for each environment, using the exact environment name from Postman (do not normalize names) + +Use the language's idiomatic construct for a string-keyed mapping — an exported object in JS/TS, a dictionary in Python, a `Map` or similar in Java/C#, a map in Go, etc. Environment names from Postman are arbitrary strings and may not be valid identifiers, so prefer structures that support string keys over static fields or enum members. + +Example (TypeScript): + +```typescript +export const variables = { + collection: { + apiVersion: "v2", + }, + Production: { + baseUrl: "https://api.example.com", + apiKey: "", + }, + Staging: { + baseUrl: "https://api-staging.example.com", + apiKey: "", + }, +}; +``` + +The caller of the generated client is responsible for selecting an environment, merging collection and environment variables, binding secrets, and passing the result to client functions. Don't do that work here. + +## Function Structure + +Generate a single exported function per API endpoint: + +- Accept all dynamic values as explicit parameters (base URL, path variables, query params, body data, auth credentials) +- Do not hardcode variable values — the caller passes them in +- Replace Postman `{{variable}}` placeholders with function parameters +- Accept base URL and URL-related variables as function parameters +- Encode path parameters and query parameters properly +- Build the complete URL from base URL + path + +## Authentication + +Implement the auth scheme from the context document (request-level, folder-level, or collection-level inheritance): + +- Accept credentials as function parameters — never hardcode them +- Support the auth type as documented (API key, Bearer token, Basic auth, etc.) + +## Response Handling + +- Parse the response payload +- If the context includes response examples, add explicit error handling for each documented status code (e.g., if the request has a 404 example, include specific 404 handling) +- Generate typed definitions for request bodies, parameters, and response shapes. Prefer the language's strongest available typing mechanism (e.g., TypeScript interfaces, JSDoc `@typedef` in JavaScript, Python TypedDicts or dataclasses, Go structs, Ruby Structs, PHP typed classes). Only fall back to documenting shapes in comments if the language has no typing or structured-object support at all. +- Follow project conventions for error handling patterns (logging, exception classes, error codes) +- Return or throw errors with meaningful context + +## Documentation + +- Add standard docstrings in the language's convention (JSDoc/TSDoc, Python docstrings, etc.) +- Include the request description from the context document if present +- Document all parameters, return types, and possible errors + +## Extracting Shared Code + +After generating multiple client files for a collection, consolidate duplicated types, auth helpers, and utility functions so they are defined once. + +- Identify duplicated code across clients in the same collection +- Extract shared code and colocate it with the collection's client files using whatever mechanism is idiomatic for the language — a `shared/` subdirectory, a sibling module, a `common` subpackage, unexported helpers in the same package, etc. +- Keep shared code scoped to a single collection by default — only share across collections if the user explicitly asks + +## Quality Verification + +Ensure generated code is lintable, production-ready, type-safe in typed languages, and follows security best practices (no hardcoded secrets, proper input validation). diff --git a/skills/postman-context/references/maintenance.md b/skills/postman-context/references/maintenance.md new file mode 100644 index 0000000..5046be5 --- /dev/null +++ b/skills/postman-context/references/maintenance.md @@ -0,0 +1,29 @@ +# API Maintenance Rules + +Installed requests include metadata linking them back to their source Postman collection and request. Use these rules to help users keep their integrations current. + +## Listing Installed Requests + +When the user wants to see what's installed, search the project for files containing "Generated by Postman Code" in a comment within the first 15 lines. Parse each file's header to extract: + +- Collection name and Collection UID +- Request path and Request UID +- Request modified-at timestamp + +Present a table showing local file path (relative to project root), collection name, request path, and last modified timestamp. + +## Checking for Updates + +When the user wants to check for API changes, scan for installed requests as above, then for each one use `getRequestContext` to fetch the current request details. Compare the updated-at timestamp from the response to the `Request modified at` timestamp in the file header. Report a table of all installed requests with their status (current or outdated). For any outdated requests, ask the user if they want to regenerate. For confirmed updates, use `getRequestCodeContext` to re-fetch context and regenerate the file in place, matching the existing code style and updating the header timestamp. + +## Finding Unused Requests + +When the user wants to clean up, scan for installed requests, then for each one search the rest of the project for imports, requires, or other references to that file (by module path, relative path, or exported function name). Report any requests with zero references. Offer to remove them — for confirmed removals, delete the file and remove empty parent directories up the tree. + +## Removing Installed Requests + +When the user wants to remove a specific request, identify the file by path, request name, or request UID. If ambiguous, list installed requests first and ask which one. Then: + +1. Delete the request file. +2. Remove empty parent directories up the tree until reaching one with contents. +3. Search the project for imports or requires referencing the deleted file. Warn the user about any broken references so they can update their code. diff --git a/skills/postman-routing/SKILL.md b/skills/postman-routing/SKILL.md deleted file mode 100644 index 8a51848..0000000 --- a/skills/postman-routing/SKILL.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -name: postman-routing -description: Automatically routes Postman and API-related requests to the correct command. Use when user mentions APIs, collections, specs, testing, mocks, docs, security, or Postman. -user-invocable: false ---- - -# Postman Command Routing - -When the user's request involves Postman or APIs, route to the appropriate command. Always prefer commands over raw MCP tool calls. Commands provide structured workflows, async handling, error diagnosis, and formatted output. - -## Routing Table - -| User Intent | Command | Why | -|-------------|---------|-----| -| Import a spec, push spec to Postman, create collection from spec | `/postman:sync` | Creates spec + collection + environment, handles async polling | -| Sync collection, update collection, keep in sync, push changes | `/postman:sync` | Full sync workflow with change reporting | -| Find API, search endpoints, what's available, is there an API for | `/postman:search` | Searches private workspace first, drills into details | -| Run tests, check if tests pass, validate API | `/postman:test` | Runs collection, parses results, diagnoses failures, suggests fixes | -| Create mock server, fake API, mock for frontend | `/postman:mock` | Checks for examples, generates missing ones, provides integration config | -| Generate docs, improve documentation, publish docs | `/postman:docs` | Analyzes completeness, fills gaps, can publish to Postman | -| Security audit, check for vulnerabilities, OWASP | `/postman:security` | 20+ security checks with severity scoring and remediation | -| Set up Postman, configure API key, first-time setup | `/postman:setup` | Guided setup with workspace verification | -| Send a request, test endpoint, hit the API, call URL | `/postman:send-request` | CLI-based HTTP requests with auth, headers, body support | -| Generate spec, create OpenAPI, document my API | `/postman:generate-spec` | Scans code for routes, generates OpenAPI YAML, validates with lint | -| Run collection tests, verify changes, check if tests pass | `/postman:run-collection` | Runs collection by cloud ID, parses results, suggests fixes | -| Explore API, install API, integrate with API, generate client from Postman collection, maintain installed requests or client code | `/postman:context` | Fetches real API definitions, generates and maintains typed client code. | -| Is my API agent-ready?, scan my API, analyze my spec | **readiness-analyzer agent** | 48 checks across 8 pillars, scoring and fix recommendations | - -## Routing Rules - -1. **Specific commands take priority.** If the intent clearly maps to one command, use it. -2. **Agent-readiness questions go to the agent.** Phrases like "agent-ready", "scan my API", "analyze my spec for AI" trigger the readiness-analyzer agent. -3. **Ambiguous requests get clarified.** If you can't determine intent, ask: "I can sync collections, generate client code, search for APIs, run tests, create mocks, generate docs, or audit security. What do you need?" -4. **Multi-step requests chain commands.** "Import my spec and run tests" = `/postman:sync` then `/postman:test`. - -## When to Use Raw MCP Tools - -Only use `mcp__postman__*` tools directly when: -- Making a single, targeted update (e.g., updating one request's body) -- The user explicitly asks to call a specific MCP tool -- The task doesn't match any command workflow diff --git a/skills/run-collection/SKILL.md b/skills/run-collection/SKILL.md index dca7e73..50a0438 100644 --- a/skills/run-collection/SKILL.md +++ b/skills/run-collection/SKILL.md @@ -1,6 +1,6 @@ --- name: run-collection -description: Run Postman collection tests using Postman CLI - use when user says "run tests", "run collection", "run my postman tests", "verify changes", "check if tests pass", or wants to execute API test suites after code changes +description: Run Postman collection tests using the Postman CLI. Use when the user wants to run collection tests, execute API test suites, or verify changes after editing code. --- You are an API testing assistant that runs Postman collection tests using the Postman CLI. diff --git a/skills/send-request/SKILL.md b/skills/send-request/SKILL.md index 52978f1..6fa1077 100644 --- a/skills/send-request/SKILL.md +++ b/skills/send-request/SKILL.md @@ -1,6 +1,6 @@ --- name: send-request -description: Send HTTP requests using Postman CLI - use when user says "send request", "test endpoint", "call API", "hit the endpoint", "make a request", "try the API", or wants to quickly test an HTTP endpoint +description: Send HTTP requests using the Postman CLI. Use when the user wants to send a request, call or test an HTTP endpoint, or quickly try an API. --- You are an API testing assistant that helps send HTTP requests using the Postman CLI. diff --git a/token-optimization-findings.md b/token-optimization-findings.md new file mode 100644 index 0000000..dba6732 --- /dev/null +++ b/token-optimization-findings.md @@ -0,0 +1,94 @@ +# Token Optimization Findings — Postman Plugin for Claude Code + +This document summarizes a token-usage review and optimization pass on the Postman Plugin for Claude Code. The plugin is pure instructional markdown, so its entire "runtime cost" is the context-window tokens it consumes in users' Claude Code sessions. Every token the plugin injects is a token the user can't spend on their actual work — and a token they pay for. + +## Where a plugin's tokens actually go + +A Claude Code plugin spends tokens in three distinct ways, and they are not equally expensive: + +1. **Always-on cost** — every skill, command, and agent `description` from the YAML front matter is injected into *every session's* system prompt, whether or not the user touches Postman. This is the most expensive token in the plugin: it's paid by every user, every session. +2. **Per-trigger cost** — when Claude decides a skill is relevant, the *entire* SKILL.md body loads into context. A 19KB skill costs ~4,800 tokens every time it fires, even if the user only needed a third of it. +3. **Runtime cost** — tool output, async polling loops, and verbose intermediate narration during command execution. + +There's also a fourth, plugin-adjacent cost: the **MCP server's tool schemas**. The Postman MCP Server's full mode exposes 100+ tools. On clients that eagerly load schemas that's roughly 40–70k tokens before the user types anything. Recent Claude Code versions defer MCP tool loading (schemas load on demand via tool search), which largely neutralizes this — but it shaped one decision below. + +## Why we did NOT switch to the smaller MCP server + +The obvious-looking fix — pointing `.mcp.json` at Postman's minimal MCP endpoint (42 tools instead of 100+) — turned out to be wrong. Reading the server's source (`enabledResources.ts` in `postmanlabs/postman-mcp-server`) showed minimal mode is missing: + +- All nine `*Context` tools (`getRequestCodeContext`, `getCollectionContext`, …) — which would silently break the plugin's flagship client-code-generation skill +- The async task polling tools (`getAsyncSpecTaskStatus`, `getStatusOfAnAsyncApiTask`) — breaking the HTTP 202 polling workflow that `sync` and `mock` depend on +- `createCollectionFolder` — the documented workaround for nesting flat collections +- `publishDocumentation` and the mock-server-response tools + +**Lesson:** measure functionality loss before chasing schema savings. Instead, the URL is now `https://mcp.postman.com/${POSTMAN_MCP_MODE:-mcp}` — full mode by default (safe because modern Claude Code defers schema loading), with an opt-in escape hatch (`minimal` or `code`) for users on older clients who don't need every workflow. + +## Changes made + +### 1. Progressive disclosure for the two largest skills + +The biggest per-trigger win. A skill doesn't need to front-load every rule it might ever apply — it needs the workflow, plus pointers to detailed rules that Claude reads with the Read tool *only at the step that needs them*. The plugin already used this pattern in one place (`agent-ready-apis` + `pillars.md`); it's now applied consistently: + +| Skill | Before | After (SKILL.md) | Moved to on-demand references | +|---|---|---|---| +| `postman-context` | 19.0KB (~4,760 tokens) | 7.7KB (~1,930 tokens) | `references/code-generation.md` (7.8KB), `references/maintenance.md` (2.1KB) | +| `generate-spec` | 10.6KB (~2,640 tokens) | 7.2KB (~1,800 tokens) | `references/spec-template.md` (2.9KB) | + +No content was deleted — the code-generation rules, maintenance rules, and OpenAPI template are intact, just deferred. A user who asks "find me an email API" no longer pays ~2,800 tokens for code-generation rules they aren't using; a user who does generate code pays the same total as before. + +**Savings: ~2,800 tokens per `postman-context` trigger and ~840 tokens per `generate-spec` trigger, in the common cases that don't need the reference material.** + +### 2. Removed the manual routing skill entirely + +The plugin shipped a `postman-routing` skill (3.3KB, ~835 tokens) whose trigger was "use when user mentions APIs" — broad enough to fire in nearly any backend coding session, Postman-related or not. Its body was a routing table that restated what every command's `description` already tells Claude. + +Modern Claude Code routes natively: it matches user intent against component descriptions. A hand-maintained routing table is duplicate state — extra tokens *and* a second place to update on every change. The skill is deleted; each component's description now carries its own routing signal. + +**Savings: ~835 tokens in every session where it fired (which, given the trigger, was most sessions in API codebases), plus its share of the always-on description block.** + +### 3. Tightened always-on front-matter descriptions + +Several descriptions enumerated long quoted trigger-phrase lists ("use when user says 'run tests', 'run collection', 'run my postman tests', …"). These were rewritten as one or two sentences stating capability + when to use, which is what Claude's router actually needs. Combined with the routing-skill removal, the always-on description block went from 3,182 to 2,562 bytes. + +**Savings: ~155 tokens in *every* session of *every* plugin user — the highest-leverage bytes in the repo.** + +### 4. Scoped `allowed-tools` from wildcard to explicit tool lists + +Every MCP command and the readiness-analyzer agent previously declared `allowed-tools: mcp__postman__*` (all 100+ tools). Each now lists exactly the tools its workflow calls — e.g. `setup` declares 6 tools, the readiness-analyzer 11 instead of 111. + +This is primarily a precision and least-privilege win, but it has real token effects: sub-agents and clients that resolve tool schemas from the allowlist load an order of magnitude fewer schemas, and a scoped list prevents the model from wandering into unrelated tools mid-command. The audit also surfaced three latent bugs: `docs` could be asked to write a markdown file without `Write` permission, and `security` and the readiness-analyzer were instructed to "apply fixes" without `Edit`/`Write`. Fixed. + +### 5. Cheaper async polling + +`generateCollection` and `syncCollectionWithSpec` return HTTP 202 and require polling. The `sync`, `mock`, and `docs` commands now instruct: poll with increasing waits (2s → 4s → 8s) and report only the final outcome instead of narrating every poll. Fewer tool round-trips, less intermediate output in context. + +### 6. Repo and docs cleanup + +- Removed the four README GIFs (out of date after these changes; they also bloated clone size, though they never cost context tokens) +- Rewrote the README: OAuth-first Quick Start, "Auto-Routing" section replaced with "Natural Language Routing" (native), documented `POSTMAN_MCP_MODE` +- Updated CLAUDE.md so future contributors keep the conventions: descriptions stay short, bulky skill content goes in `references/`, `allowed-tools` lists explicit tool names + +## Estimated impact + +Using the ~4 characters/token rule of thumb: + +| Change | Who pays today | Saving | +|---|---|---| +| Routing skill removed | Nearly every session in an API codebase | ~835 tokens/session | +| Description trims | Every session, every user | ~155 tokens/session | +| `postman-context` split | Every session that triggers the skill | up to ~2,800 tokens/trigger | +| `generate-spec` split | Every session that triggers the skill | up to ~840 tokens/trigger | +| Scoped `allowed-tools` | Sub-agent spawns; older/eager clients | up to ~10s of thousands of tokens on eager-loading clients; precision win elsewhere | +| `POSTMAN_MCP_MODE` opt-in | Users on older clients who opt in | ~40–70k tokens/session (minimal/code vs full, eager loading) | +| Polling + drill-down guidance | Long-running sync/mock/docs runs | variable; fewer round-trips and less narration | + +A typical "explore an API and generate a client" session that previously loaded the routing skill plus the full `postman-context` skill saves roughly **3,600 tokens** before any work happens; a session that never touches Postman saves ~990 tokens it used to spend on routing overhead. + +## Takeaways for plugin authors + +1. **Treat front-matter descriptions as the most expensive real estate you own.** They're injected into every session. One or two sentences: what it does, when to use it. +2. **Progressive disclosure beats monolithic skills.** Keep SKILL.md to the workflow (~6KB or less); move templates, rule catalogs, and edge-case handling to `references/*.md` that the skill reads on demand. +3. **Don't build what the harness already does.** A routing skill duplicating Claude's native description-based routing costs tokens twice and creates a maintenance hazard. +4. **Verify before downsizing an MCP server.** Smaller tool modes can silently drop the exact tools your workflows depend on — read the server's tool manifest, don't guess. +5. **Scope `allowed-tools` to what each component calls.** It's least-privilege hygiene, it loads fewer schemas where that matters, and the audit itself tends to find permission bugs. +6. **Make polling cheap.** Any 202-style async workflow should specify backoff and final-result-only reporting, or the model will happily narrate every poll.