From c1ad27c78cdea78bac69397f564548d73ec0f505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diego=20Garc=C3=ADa?= Date: Mon, 4 Aug 2025 13:25:50 +0200 Subject: [PATCH] refactor: version `dist/` folder --- .gitignore | 1 - README.md | 2 +- dist/package.json | 46 + dist/src/clients/postman.js | 39 + dist/src/index.js | 128 +++ dist/src/tests/integration/direct.test.js | 225 +++++ .../integration/factories/dataFactory.js | 98 ++ .../tests/integration/test-data-factory.js | 203 ++++ dist/src/tools/create_collection.js | 810 ++++++++++++++++ dist/src/tools/create_collection_comment.js | 65 ++ dist/src/tools/create_collection_folder.js | 50 + dist/src/tools/create_collection_fork.js | 47 + dist/src/tools/create_collection_request.js | 53 + dist/src/tools/create_collection_response.js | 50 + dist/src/tools/create_environment.js | 59 ++ dist/src/tools/create_folder_comment.js | 66 ++ dist/src/tools/create_mock.js | 59 ++ dist/src/tools/create_monitor.js | 148 +++ dist/src/tools/create_request_comment.js | 68 ++ dist/src/tools/create_response_comment.js | 66 ++ dist/src/tools/create_spec.js | 59 ++ dist/src/tools/create_update_spec_file.js | 45 + dist/src/tools/create_workspace.js | 53 + .../tools/delete_api_collection_comment.js | 40 + dist/src/tools/delete_collection.js | 40 + dist/src/tools/delete_collection_comment.js | 39 + dist/src/tools/delete_collection_folder.js | 39 + dist/src/tools/delete_collection_request.js | 39 + dist/src/tools/delete_collection_response.js | 39 + dist/src/tools/delete_environment.js | 36 + dist/src/tools/delete_folder_comment.js | 40 + dist/src/tools/delete_mock.js | 36 + dist/src/tools/delete_monitor.js | 36 + .../src/tools/delete_pan_element_or_folder.js | 41 + dist/src/tools/delete_request_comment.js | 40 + dist/src/tools/delete_response_comment.js | 40 + dist/src/tools/delete_spec.js | 36 + dist/src/tools/delete_workspace.js | 36 + dist/src/tools/duplicate_collection.js | 50 + dist/src/tools/generate_collection.js | 88 ++ .../tools/generate_spec_from_collection.js | 51 + .../src/tools/get_all_elements_and_folders.js | 122 +++ .../tools/get_all_pan_add_element_requests.js | 99 ++ dist/src/tools/get_all_specs.js | 53 + dist/src/tools/get_async_spec_task_status.js | 40 + dist/src/tools/get_authenticated_user.js | 36 + dist/src/tools/get_collection.js | 52 + dist/src/tools/get_collection_comments.js | 38 + dist/src/tools/get_collection_folder.js | 54 ++ dist/src/tools/get_collection_forks.js | 57 ++ dist/src/tools/get_collection_request.js | 54 ++ dist/src/tools/get_collection_response.js | 54 ++ dist/src/tools/get_collection_tags.js | 38 + .../src/tools/get_collection_updates_tasks.js | 36 + dist/src/tools/get_collections.js | 57 ++ .../tools/get_collections_forked_by_user.js | 56 ++ .../get_duplicate_collection_task_status.js | 36 + dist/src/tools/get_environment.js | 36 + dist/src/tools/get_environments.js | 40 + dist/src/tools/get_folder_comments.js | 39 + .../tools/get_generated_collection_specs.js | 39 + dist/src/tools/get_mock.js | 36 + dist/src/tools/get_mocks.js | 43 + dist/src/tools/get_monitor.js | 36 + dist/src/tools/get_monitors.js | 72 ++ dist/src/tools/get_request_comments.js | 41 + dist/src/tools/get_response_comments.js | 39 + .../src/tools/get_source_collection_status.js | 36 + dist/src/tools/get_spec.js | 36 + dist/src/tools/get_spec_collections.js | 52 + dist/src/tools/get_spec_definition.js | 36 + dist/src/tools/get_status_of_an_async_task.js | 42 + dist/src/tools/get_tagged_entities.js | 69 ++ dist/src/tools/get_workspace.js | 44 + .../tools/get_workspace_global_variables.js | 36 + dist/src/tools/get_workspace_tags.js | 36 + dist/src/tools/get_workspaces.js | 56 ++ dist/src/tools/patch_collection.js | 318 ++++++ dist/src/tools/patch_environment.js | 36 + dist/src/tools/post_pan_element_or_folder.js | 36 + dist/src/tools/publish_documentation.js | 123 +++ dist/src/tools/publish_mock.js | 36 + dist/src/tools/pull_collection_changes.js | 36 + dist/src/tools/put_collection.js | 913 ++++++++++++++++++ dist/src/tools/put_environment.js | 57 ++ dist/src/tools/resolve_comment_thread.js | 38 + dist/src/tools/run_monitor.js | 44 + dist/src/tools/sync_collection_with_spec.js | 41 + dist/src/tools/sync_spec_with_collection.js | 41 + dist/src/tools/transfer_collection_folders.js | 78 ++ .../src/tools/transfer_collection_requests.js | 78 ++ .../tools/transfer_collection_responses.js | 78 ++ dist/src/tools/unpublish_documentation.js | 38 + dist/src/tools/unpublish_mock.js | 36 + .../tools/update_api_collection_comment.js | 60 ++ dist/src/tools/update_collection_comment.js | 59 ++ dist/src/tools/update_collection_folder.js | 48 + dist/src/tools/update_collection_request.js | 67 ++ dist/src/tools/update_collection_response.js | 54 ++ dist/src/tools/update_collection_tags.js | 57 ++ dist/src/tools/update_folder_comment.js | 60 ++ dist/src/tools/update_mock.js | 65 ++ dist/src/tools/update_monitor.js | 142 +++ .../src/tools/update_pan_element_or_folder.js | 41 + dist/src/tools/update_request_comment.js | 60 ++ dist/src/tools/update_response_comment.js | 60 ++ dist/src/tools/update_spec_properties.js | 44 + dist/src/tools/update_workspace.js | 54 ++ .../update_workspace_global_variables.js | 57 ++ dist/src/tools/update_workspace_tags.js | 57 ++ 110 files changed, 7962 insertions(+), 2 deletions(-) create mode 100644 dist/package.json create mode 100644 dist/src/clients/postman.js create mode 100644 dist/src/index.js create mode 100644 dist/src/tests/integration/direct.test.js create mode 100644 dist/src/tests/integration/factories/dataFactory.js create mode 100644 dist/src/tests/integration/test-data-factory.js create mode 100644 dist/src/tools/create_collection.js create mode 100644 dist/src/tools/create_collection_comment.js create mode 100644 dist/src/tools/create_collection_folder.js create mode 100644 dist/src/tools/create_collection_fork.js create mode 100644 dist/src/tools/create_collection_request.js create mode 100644 dist/src/tools/create_collection_response.js create mode 100644 dist/src/tools/create_environment.js create mode 100644 dist/src/tools/create_folder_comment.js create mode 100644 dist/src/tools/create_mock.js create mode 100644 dist/src/tools/create_monitor.js create mode 100644 dist/src/tools/create_request_comment.js create mode 100644 dist/src/tools/create_response_comment.js create mode 100644 dist/src/tools/create_spec.js create mode 100644 dist/src/tools/create_update_spec_file.js create mode 100644 dist/src/tools/create_workspace.js create mode 100644 dist/src/tools/delete_api_collection_comment.js create mode 100644 dist/src/tools/delete_collection.js create mode 100644 dist/src/tools/delete_collection_comment.js create mode 100644 dist/src/tools/delete_collection_folder.js create mode 100644 dist/src/tools/delete_collection_request.js create mode 100644 dist/src/tools/delete_collection_response.js create mode 100644 dist/src/tools/delete_environment.js create mode 100644 dist/src/tools/delete_folder_comment.js create mode 100644 dist/src/tools/delete_mock.js create mode 100644 dist/src/tools/delete_monitor.js create mode 100644 dist/src/tools/delete_pan_element_or_folder.js create mode 100644 dist/src/tools/delete_request_comment.js create mode 100644 dist/src/tools/delete_response_comment.js create mode 100644 dist/src/tools/delete_spec.js create mode 100644 dist/src/tools/delete_workspace.js create mode 100644 dist/src/tools/duplicate_collection.js create mode 100644 dist/src/tools/generate_collection.js create mode 100644 dist/src/tools/generate_spec_from_collection.js create mode 100644 dist/src/tools/get_all_elements_and_folders.js create mode 100644 dist/src/tools/get_all_pan_add_element_requests.js create mode 100644 dist/src/tools/get_all_specs.js create mode 100644 dist/src/tools/get_async_spec_task_status.js create mode 100644 dist/src/tools/get_authenticated_user.js create mode 100644 dist/src/tools/get_collection.js create mode 100644 dist/src/tools/get_collection_comments.js create mode 100644 dist/src/tools/get_collection_folder.js create mode 100644 dist/src/tools/get_collection_forks.js create mode 100644 dist/src/tools/get_collection_request.js create mode 100644 dist/src/tools/get_collection_response.js create mode 100644 dist/src/tools/get_collection_tags.js create mode 100644 dist/src/tools/get_collection_updates_tasks.js create mode 100644 dist/src/tools/get_collections.js create mode 100644 dist/src/tools/get_collections_forked_by_user.js create mode 100644 dist/src/tools/get_duplicate_collection_task_status.js create mode 100644 dist/src/tools/get_environment.js create mode 100644 dist/src/tools/get_environments.js create mode 100644 dist/src/tools/get_folder_comments.js create mode 100644 dist/src/tools/get_generated_collection_specs.js create mode 100644 dist/src/tools/get_mock.js create mode 100644 dist/src/tools/get_mocks.js create mode 100644 dist/src/tools/get_monitor.js create mode 100644 dist/src/tools/get_monitors.js create mode 100644 dist/src/tools/get_request_comments.js create mode 100644 dist/src/tools/get_response_comments.js create mode 100644 dist/src/tools/get_source_collection_status.js create mode 100644 dist/src/tools/get_spec.js create mode 100644 dist/src/tools/get_spec_collections.js create mode 100644 dist/src/tools/get_spec_definition.js create mode 100644 dist/src/tools/get_status_of_an_async_task.js create mode 100644 dist/src/tools/get_tagged_entities.js create mode 100644 dist/src/tools/get_workspace.js create mode 100644 dist/src/tools/get_workspace_global_variables.js create mode 100644 dist/src/tools/get_workspace_tags.js create mode 100644 dist/src/tools/get_workspaces.js create mode 100644 dist/src/tools/patch_collection.js create mode 100644 dist/src/tools/patch_environment.js create mode 100644 dist/src/tools/post_pan_element_or_folder.js create mode 100644 dist/src/tools/publish_documentation.js create mode 100644 dist/src/tools/publish_mock.js create mode 100644 dist/src/tools/pull_collection_changes.js create mode 100644 dist/src/tools/put_collection.js create mode 100644 dist/src/tools/put_environment.js create mode 100644 dist/src/tools/resolve_comment_thread.js create mode 100644 dist/src/tools/run_monitor.js create mode 100644 dist/src/tools/sync_collection_with_spec.js create mode 100644 dist/src/tools/sync_spec_with_collection.js create mode 100644 dist/src/tools/transfer_collection_folders.js create mode 100644 dist/src/tools/transfer_collection_requests.js create mode 100644 dist/src/tools/transfer_collection_responses.js create mode 100644 dist/src/tools/unpublish_documentation.js create mode 100644 dist/src/tools/unpublish_mock.js create mode 100644 dist/src/tools/update_api_collection_comment.js create mode 100644 dist/src/tools/update_collection_comment.js create mode 100644 dist/src/tools/update_collection_folder.js create mode 100644 dist/src/tools/update_collection_request.js create mode 100644 dist/src/tools/update_collection_response.js create mode 100644 dist/src/tools/update_collection_tags.js create mode 100644 dist/src/tools/update_folder_comment.js create mode 100644 dist/src/tools/update_mock.js create mode 100644 dist/src/tools/update_monitor.js create mode 100644 dist/src/tools/update_pan_element_or_folder.js create mode 100644 dist/src/tools/update_request_comment.js create mode 100644 dist/src/tools/update_response_comment.js create mode 100644 dist/src/tools/update_spec_properties.js create mode 100644 dist/src/tools/update_workspace.js create mode 100644 dist/src/tools/update_workspace_global_variables.js create mode 100644 dist/src/tools/update_workspace_tags.js diff --git a/.gitignore b/.gitignore index 36dd90d..b0060f4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ -dist/ node_modules/ *-benchmark-results.json \ No newline at end of file diff --git a/README.md b/README.md index ecd0d68..cd69463 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ You can integrate your MCP server with Visual Studio Code to use it with VS Code - **postman-api-mcp**: Uses the local stdio-based server, running directly from your project files. - Clone the repository - - In the repository root folder, execute `npm install && npm run build`. This compiles the server code in the `dist` folder. + - In the repository root folder, execute `npm install`. This will install all the required dependencies. - Make sure to replace `${workspaceFolder}` in the mcp.json file with the full path to the Postman MCP repository. 4. When prompted, enter your Postman API key. diff --git a/dist/package.json b/dist/package.json new file mode 100644 index 0000000..ca17a3a --- /dev/null +++ b/dist/package.json @@ -0,0 +1,46 @@ +{ + "name": "postman-api-mcp", + "version": "1.0.1", + "description": "A simple MCP server to operate on the Postman API", + "main": "index.js", + "type": "module", + "scripts": { + "start": "node dist/src/index.js --sse", + "start:dev": "tsx src/index.ts --sse", + "start:stdio": "node dist/src/index.js", + "build": "eslint --fix ./src && prettier --write \"src/**/*.ts\" && tsc", + "test": "vitest", + "lint": "eslint", + "lint:fix": "eslint --fix" + }, + "dependencies": { + "@apidevtools/swagger-parser": "^11.0.0", + "@modelcontextprotocol/sdk": "^1.17.0", + "dotenv": "^16.5.0", + "es-toolkit": "^1.37.2", + "express": "^5.1.0" + }, + "devDependencies": { + "@eslint/js": "^9.26.0", + "@types/express": "^5.0.1", + "@types/node": "^22", + "eslint": "^9.26.0", + "eslint-config-prettier": "^10.1.5", + "eslint-plugin-prettier": "^5.4.0", + "eslint-plugin-unused-imports": "^4.1.4", + "fs-extra": "^11.3.0", + "jest": "^29.7.0", + "json-schema-to-zod": "^2.6.1", + "openapi-types": "^12.1.3", + "prettier": "^3.5.3", + "tsx": "^4.19.4", + "typescript": "^5.8.3", + "typescript-eslint": "^8.32.1", + "vitest": "^3.2.4" + }, + "engines": { + "node": ">=20.0.0" + }, + "author": "Postman, Inc.", + "license": "Apache-2.0" +} diff --git a/dist/src/clients/postman.js b/dist/src/clients/postman.js new file mode 100644 index 0000000..fc29128 --- /dev/null +++ b/dist/src/clients/postman.js @@ -0,0 +1,39 @@ +import packageJson from '../../package.json' with { type: 'json' }; +const BASE_URL = 'https://api.postman.com'; +export var ContentType; +(function (ContentType) { + ContentType["Json"] = "application/json"; + ContentType["JsonPatch"] = "application/json-patch+json"; +})(ContentType || (ContentType = {})); +export async function fetchPostmanAPI(endpoint, options) { + const apiKey = options.apiKey || process.env.POSTMAN_API_KEY; + if (!apiKey) { + throw new Error('API key is required.'); + } + const contentType = options.contentType || ContentType.Json; + const userAgentHeader = options.headers && 'user-agent' in options.headers + ? `${options.headers['user-agent']}/${packageJson.name}/${packageJson.version}` + : `${packageJson.name}/${packageJson.version}`; + const headers = { + ...options.headers, + 'content-type': contentType, + 'x-api-key': apiKey, + 'user-agent': userAgentHeader, + }; + const { headers: _, ...optionsWithoutHeaders } = options; + const response = await fetch(`${BASE_URL}${endpoint}`, { + ...optionsWithoutHeaders, + headers, + }); + if (!response.ok) { + const errorText = await response.text(); + throw new Error(`API request failed: ${response.status} ${errorText}`); + } + if (response.status === 204) + return null; + const responseContentType = response.headers.get('content-type') || ''; + if (responseContentType.includes('application/json')) { + return response.json(); + } + return response.text(); +} diff --git a/dist/src/index.js b/dist/src/index.js new file mode 100644 index 0000000..5d094a3 --- /dev/null +++ b/dist/src/index.js @@ -0,0 +1,128 @@ +#!/usr/bin/env tsx +import dotenv from 'dotenv'; +import { Server } from '@modelcontextprotocol/sdk/server/index.js'; +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; +import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from '@modelcontextprotocol/sdk/types.js'; +import zodToJsonSchema from 'zod-to-json-schema'; +import packageJson from '../package.json' with { type: 'json' }; +import { readdir } from 'node:fs/promises'; +import { join, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; +async function loadAllTools() { + const __filename = fileURLToPath(import.meta.url); + const __dirname = dirname(__filename); + const toolsDir = join(__dirname, 'tools'); + try { + const files = await readdir(toolsDir); + const toolFiles = files.filter((file) => file.endsWith('.js')); + const tools = []; + for (const file of toolFiles) { + try { + const toolPath = join(toolsDir, file); + const isWindows = process.platform === 'win32'; + const toolModule = await import(isWindows ? `file://${toolPath}` : toolPath); + if (toolModule.method && + toolModule.description && + toolModule.parameters && + toolModule.handler) { + tools.push(toolModule); + } + else { + console.warn(`Tool module ${file} is missing required exports. Skipping.`); + } + } + catch (error) { + console.error(`Failed to load tool ${file}:`, error); + } + } + return tools; + } + catch (error) { + console.error('Failed to read tools directory:', error); + return []; + } +} +dotenv.config(); +const SERVER_NAME = packageJson.name; +const APP_VERSION = packageJson.version; +export const USER_AGENT = `${SERVER_NAME}/${APP_VERSION}`; +const logger = { + timestamp() { + return new Date().toISOString(); + }, + info(message, sessionId = null) { + const sessionPart = sessionId ? `[SessionId: ${sessionId}] ` : ''; + console.log(`[${this.timestamp()}] [INFO] ${sessionPart}${message}`); + }, + debug(message, sessionId = null) { + const sessionPart = sessionId ? `[SessionId: ${sessionId}] ` : ''; + console.log(`[${this.timestamp()}] [DEBUG] ${sessionPart}${message}`); + }, + warn(message, sessionId = null) { + const sessionPart = sessionId ? `[SessionId: ${sessionId}] ` : ''; + console.warn(`[${this.timestamp()}] [WARN] ${sessionPart}${message}`); + }, + error(message, error = null, sessionId = null) { + const sessionPart = sessionId ? `[SessionId: ${sessionId}] ` : ''; + console.error(`[${this.timestamp()}] [ERROR] ${sessionPart}${message}`, error || ''); + }, +}; +let currentApiKey = undefined; +const allGeneratedTools = await loadAllTools(); +logger.info(`Dynamically loaded ${allGeneratedTools.length} tools...`); +async function run() { + logger.info(`Transport mode: Stdio`); + const server = new Server({ name: SERVER_NAME, version: APP_VERSION }, { capabilities: { tools: {} } }); + server.onerror = (error) => logger.error('[MCP Server Error]', error); + process.on('SIGINT', async () => { + logger.info('SIGINT received, shutting down server...'); + await server.close(); + process.exit(0); + }); + logger.info(`Registering ${allGeneratedTools.length} tools...`); + server.setRequestHandler(CallToolRequestSchema, async (request, extra) => { + const toolName = request.params.name; + const tool = allGeneratedTools.find((t) => t.method === toolName); + if (!tool) { + throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${toolName}`); + } + const args = request.params.arguments || {}; + try { + if (!currentApiKey) { + throw new McpError(ErrorCode.InvalidParams, 'API key is required.'); + } + const result = await tool.handler(args, { + apiKey: currentApiKey, + headers: extra.requestInfo?.headers, + }); + return result; + } + catch (error) { + throw new McpError(ErrorCode.InternalError, `API error: ${error.message}`, { + originalError: error, + }); + } + }); + server.setRequestHandler(ListToolsRequestSchema, async () => { + const transformedTools = allGeneratedTools.map((tool) => ({ + name: tool.method, + description: tool.description, + inputSchema: zodToJsonSchema(tool.parameters), + annotations: tool.annotations, + })); + return { tools: transformedTools }; + }); + currentApiKey = process.env.POSTMAN_API_KEY; + if (!currentApiKey) { + logger.error('API key is required. Set the POSTMAN_API_KEY environment variable.'); + process.exit(1); + } + logger.info(`[${SERVER_NAME} - Stdio Transport] running.`); + const transport = new StdioServerTransport(); + await server.connect(transport); + logger.info('Stdio transport connected. Waiting for messages...'); +} +run().catch((error) => { + logger.error('Unhandled error during server execution:', error); + process.exit(1); +}); diff --git a/dist/src/tests/integration/direct.test.js b/dist/src/tests/integration/direct.test.js new file mode 100644 index 0000000..fc475cd --- /dev/null +++ b/dist/src/tests/integration/direct.test.js @@ -0,0 +1,225 @@ +import { describe, it, expect, beforeAll, afterAll, beforeEach, afterEach } from 'vitest'; +import { Client } from '@modelcontextprotocol/sdk/client/index.js'; +import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'; +import { spawn } from 'child_process'; +import { WorkspaceDataFactory, EnvironmentDataFactory, } from './factories/dataFactory.js'; +describe('Postman MCP - Direct Integration Tests', () => { + let client; + let serverProcess; + let createdWorkspaceIds = []; + let createdEnvironmentIds = []; + beforeAll(async () => { + console.log('๐Ÿš€ Starting Postman MCP server for integration tests...'); + const cleanEnv = Object.fromEntries(Object.entries(process.env).filter(([_, value]) => value !== undefined)); + cleanEnv.NODE_ENV = 'test'; + serverProcess = spawn('node', ['dist/src/index.js'], { + stdio: ['pipe', 'pipe', 'pipe'], + env: cleanEnv, + }); + await new Promise((resolve) => setTimeout(resolve, 3000)); + client = new Client({ + name: 'integration-test-client', + version: '1.0.0', + }, { + capabilities: { + tools: {}, + }, + }); + const transport = new StdioClientTransport({ + command: 'node', + args: ['dist/src/index.js'], + env: cleanEnv, + }); + await client.connect(transport); + console.log('โœ… Connected to MCP server'); + }, 30000); + afterAll(async () => { + await cleanupAllTestResources(); + if (client) { + await client.close(); + } + if (serverProcess && !serverProcess.killed) { + serverProcess.kill(); + await new Promise((resolve) => setTimeout(resolve, 1000)); + } + console.log('๐Ÿงน Integration test cleanup completed'); + }, 30000); + beforeEach(() => { + createdWorkspaceIds = []; + createdEnvironmentIds = []; + }); + afterEach(async () => { + await cleanupTestWorkspaces(createdWorkspaceIds); + await cleanupTestEnvironments(createdEnvironmentIds); + createdWorkspaceIds = []; + createdEnvironmentIds = []; + }); + describe('Workspace Workflow', () => { + it('should create, list, search, update, and delete a single workspace', async () => { + const workspaceData = WorkspaceDataFactory.createWorkspace(); + const workspaceId = await createWorkspace(workspaceData); + createdWorkspaceIds.push(workspaceId); + expect(createdWorkspaceIds).toHaveLength(1); + expect(createdWorkspaceIds[0]).toBe(workspaceId); + const listResult = await client.callTool({ + name: 'get-workspaces', + arguments: {}, + }); + expect(WorkspaceDataFactory.validateResponse(listResult)).toBe(true); + expect(listResult.content[0].text).toContain(workspaceId); + const searchResult = await client.callTool({ + name: 'get-workspace', + arguments: { workspaceId }, + }); + expect(WorkspaceDataFactory.validateResponse(searchResult)).toBe(true); + expect(searchResult.content[0].text).toContain(workspaceData.name); + const updatedName = '[Integration Test] Updated Workspace'; + const updateResult = await client.callTool({ + name: 'update-workspace', + arguments: { + workspaceId, + workspace: { name: updatedName, type: 'personal' }, + }, + }); + expect(WorkspaceDataFactory.validateResponse(updateResult)).toBe(true); + const verifyUpdateResult = await client.callTool({ + name: 'get-workspace', + arguments: { + workspaceId, + }, + }); + expect(WorkspaceDataFactory.validateResponse(verifyUpdateResult)).toBe(true); + expect(verifyUpdateResult.content[0].text).toContain(updatedName); + }); + }); + describe('Environment Workflow', () => { + it('should create, list, search, update, and delete a single environment', async () => { + const environmentData = EnvironmentDataFactory.createEnvironment(); + const environmentId = await createEnvironment(environmentData); + createdEnvironmentIds.push(environmentId); + expect(createdEnvironmentIds).toHaveLength(1); + expect(createdEnvironmentIds[0]).toBe(environmentId); + const listResult = await client.callTool({ + name: 'get-environments', + arguments: {}, + }); + expect(EnvironmentDataFactory.validateResponse(listResult)).toBe(true); + expect(listResult.content[0].text).toContain(environmentId); + const getResult = await client.callTool({ + name: 'get-environment', + arguments: { environmentId }, + }); + expect(EnvironmentDataFactory.validateResponse(getResult)).toBe(true); + expect(getResult.content[0].text).toContain(environmentData.name); + const updatedName = '[Integration Test] Updated Environment'; + const updatedEnvironment = { + name: updatedName, + values: [ + { + enabled: true, + key: 'updated_var', + value: 'updated_value', + type: 'default', + }, + ], + }; + const updateResult = await client.callTool({ + name: 'put-environment', + arguments: { + environmentId, + environment: updatedEnvironment, + }, + }); + expect(EnvironmentDataFactory.validateResponse(updateResult)).toBe(true); + const verifyUpdateResult = await client.callTool({ + name: 'get-environment', + arguments: { + environmentId, + }, + }); + expect(EnvironmentDataFactory.validateResponse(verifyUpdateResult)).toBe(true); + expect(verifyUpdateResult.content[0].text).toContain(updatedName); + expect(verifyUpdateResult.content[0].text).toContain('updated_var'); + }); + it('should create and delete a minimal environment', async () => { + const environmentData = EnvironmentDataFactory.createMinimalEnvironment(); + const environmentId = await createEnvironment(environmentData); + createdEnvironmentIds.push(environmentId); + const getResult = await client.callTool({ + name: 'get-environment', + arguments: { environmentId }, + }); + expect(EnvironmentDataFactory.validateResponse(getResult)).toBe(true); + expect(getResult.content[0].text).toContain(environmentData.name); + }); + }); + async function createWorkspace(workspaceData) { + const result = await client.callTool({ + name: 'create-workspace', + arguments: { + workspace: workspaceData, + }, + }); + if (result.isError) { + throw new Error(result.content[0].text); + } + expect(WorkspaceDataFactory.validateResponse(result)).toBe(true); + const workspaceId = WorkspaceDataFactory.extractIdFromResponse(result); + if (!workspaceId) { + throw new Error(`Workspace ID not found in response: ${JSON.stringify(result)}`); + } + return workspaceId; + } + async function createEnvironment(environmentData) { + const result = await client.callTool({ + name: 'create-environment', + arguments: { + environment: environmentData, + }, + }); + if (result.isError) { + throw new Error(result.content[0].text); + } + expect(EnvironmentDataFactory.validateResponse(result)).toBe(true); + const environmentId = EnvironmentDataFactory.extractIdFromResponse(result); + if (!environmentId) { + throw new Error(`Environment ID not found in response: ${JSON.stringify(result)}`); + } + return environmentId; + } + async function cleanupTestWorkspaces(workspaceIds) { + for (const workspaceId of workspaceIds) { + try { + await client.callTool({ + name: 'delete-workspace', + arguments: { + workspaceId, + }, + }); + } + catch (error) { + console.warn(`Failed to cleanup workspace ${workspaceId}:`, String(error)); + } + } + } + async function cleanupTestEnvironments(environmentIds) { + for (const environmentId of environmentIds) { + try { + await client.callTool({ + name: 'delete-environment', + arguments: { + environmentId, + }, + }); + } + catch (error) { + console.warn(`Failed to cleanup environment ${environmentId}:`, String(error)); + } + } + } + async function cleanupAllTestResources() { + console.log('Cleaning up all test resources...'); + await cleanupTestWorkspaces(createdWorkspaceIds); + await cleanupTestEnvironments(createdEnvironmentIds); + } +}); diff --git a/dist/src/tests/integration/factories/dataFactory.js b/dist/src/tests/integration/factories/dataFactory.js new file mode 100644 index 0000000..56ed2c2 --- /dev/null +++ b/dist/src/tests/integration/factories/dataFactory.js @@ -0,0 +1,98 @@ +export class TestDataFactory { + createdIds = []; + addCreatedId(id) { + this.createdIds.push(id); + } + getCreatedIds() { + return [...this.createdIds]; + } + clearCreatedIds() { + this.createdIds = []; + } +} +export class WorkspaceDataFactory extends TestDataFactory { + static createWorkspace(overrides = {}) { + return { + name: '[Integration Test] Test Workspace', + description: 'Created by integration test suite', + type: 'personal', + ...overrides, + }; + } + static validateResponse(response) { + if (!response || !response.content || !Array.isArray(response.content)) { + return false; + } + const text = response.content[0]?.text; + return typeof text === 'string'; + } + static extractIdFromResponse(response) { + const text = response.content[0]?.text; + if (!text) + return null; + try { + const parsed = JSON.parse(text); + if (parsed.workspace?.id) { + return parsed.workspace.id; + } + else if (parsed.id) { + return parsed.id; + } + const pattern = /"id": "([a-zA-Z0-9_-]+)"/; + const match = text.match(pattern); + return match ? match[1] : null; + } + catch { + const pattern = /"id": "([a-zA-Z0-9_-]+)"/; + const match = text.match(pattern); + return match ? match[1] : null; + } + } +} +export class EnvironmentDataFactory extends TestDataFactory { + static createEnvironment(overrides = {}) { + return { + name: '[Integration Test] Test Environment', + values: [ + { enabled: true, key: 'test_var', value: 'test_value', type: 'default' }, + { enabled: true, key: 'api_url', value: 'https://api.example.com', type: 'default' }, + ], + ...overrides, + }; + } + static createMinimalEnvironment(overrides = {}) { + return { + name: '[Integration Test] Minimal Environment', + ...overrides, + }; + } + static validateResponse(response) { + if (!response || !response.content || !Array.isArray(response.content)) { + return false; + } + const text = response.content[0]?.text; + return typeof text === 'string'; + } + static extractIdFromResponse(response) { + const text = response.content[0]?.text; + if (!text) + return null; + try { + const parsed = JSON.parse(text); + if (parsed.environment?.id) { + return parsed.environment.id; + } + else if (parsed.id) { + return parsed.id; + } + const pattern = /"id": "([a-zA-Z0-9_-]+)"/; + const match = text.match(pattern); + return match ? match[1] : null; + } + catch { + const pattern = /"id": "([a-zA-Z0-9_-]+)"/; + const match = text.match(pattern); + return match ? match[1] : null; + } + } +} diff --git a/dist/src/tests/integration/test-data-factory.js b/dist/src/tests/integration/test-data-factory.js new file mode 100644 index 0000000..5179de2 --- /dev/null +++ b/dist/src/tests/integration/test-data-factory.js @@ -0,0 +1,203 @@ +export class TestDataFactory { + static TEST_CALENDAR_ID = process.env.TEST_CALENDAR_ID || 'primary'; + createdEventIds = []; + createdWorkspaceIds = []; + performanceMetrics = []; + static getTestCalendarId() { + return TestDataFactory.TEST_CALENDAR_ID; + } + static createWorkspace(overrides = {}) { + return { + name: '[Integration Test] Test Workspace', + description: 'Created by integration test suite', + type: 'personal', + ...overrides, + }; + } + static formatDateTimeRFC3339(date) { + const isoString = date.toISOString(); + return isoString.replace(/\.\d{3}Z$/, ''); + } + static formatDateTimeRFC3339WithTimezone(date) { + return date.toISOString().replace(/\.\d{3}Z$/, 'Z'); + } + static createSingleEvent(overrides = {}) { + const now = new Date(); + const start = new Date(now.getTime() + 2 * 60 * 60 * 1000); + const end = new Date(start.getTime() + 60 * 60 * 1000); + return { + summary: 'Test Integration Event', + description: 'Created by integration test suite', + start: this.formatDateTimeRFC3339(start), + end: this.formatDateTimeRFC3339(end), + timeZone: 'America/Los_Angeles', + location: 'Test Conference Room', + reminders: { + useDefault: false, + overrides: [{ method: 'popup', minutes: 15 }], + }, + ...overrides, + }; + } + static createAllDayEvent(overrides = {}) { + const tomorrow = new Date(); + tomorrow.setDate(tomorrow.getDate() + 1); + tomorrow.setHours(0, 0, 0, 0); + const dayAfter = new Date(tomorrow); + dayAfter.setDate(dayAfter.getDate() + 1); + dayAfter.setHours(0, 0, 0, 0); + return { + summary: 'Test All-Day Event', + description: 'All-day test event', + start: this.formatDateTimeRFC3339(tomorrow), + end: this.formatDateTimeRFC3339(dayAfter), + timeZone: 'America/Los_Angeles', + ...overrides, + }; + } + static createRecurringEvent(overrides = {}) { + const start = new Date(); + start.setDate(start.getDate() + 1); + start.setHours(10, 0, 0, 0); + const end = new Date(start); + end.setHours(11, 0, 0, 0); + return { + summary: 'Test Recurring Meeting', + description: 'Weekly recurring test meeting', + start: this.formatDateTimeRFC3339(start), + end: this.formatDateTimeRFC3339(end), + timeZone: 'America/Los_Angeles', + location: 'Recurring Meeting Room', + recurrence: ['RRULE:FREQ=WEEKLY;COUNT=5'], + reminders: { + useDefault: false, + overrides: [{ method: 'email', minutes: 1440 }], + }, + ...overrides, + }; + } + static createEventWithAttendees(overrides = {}) { + const invitee1 = process.env.INVITEE_1; + const invitee2 = process.env.INVITEE_2; + if (!invitee1 || !invitee2) { + throw new Error('INVITEE_1 and INVITEE_2 environment variables are required for creating events with attendees'); + } + return this.createSingleEvent({ + summary: 'Test Meeting with Attendees', + attendees: [{ email: invitee1 }, { email: invitee2 }], + ...overrides, + }); + } + static createColoredEvent(colorId, overrides = {}) { + return this.createSingleEvent({ + summary: `Test Event - Color ${colorId}`, + colorId, + ...overrides, + }); + } + static getTimeRanges() { + const now = new Date(); + return { + pastWeek: { + timeMin: this.formatDateTimeRFC3339WithTimezone(new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000)), + timeMax: this.formatDateTimeRFC3339WithTimezone(now), + }, + nextWeek: { + timeMin: this.formatDateTimeRFC3339WithTimezone(now), + timeMax: this.formatDateTimeRFC3339WithTimezone(new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000)), + }, + nextMonth: { + timeMin: this.formatDateTimeRFC3339WithTimezone(now), + timeMax: this.formatDateTimeRFC3339WithTimezone(new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000)), + }, + threeMonths: { + timeMin: this.formatDateTimeRFC3339WithTimezone(now), + timeMax: this.formatDateTimeRFC3339WithTimezone(new Date(now.getTime() + 90 * 24 * 60 * 60 * 1000)), + }, + }; + } + startTimer(operation) { + return Date.now(); + } + endTimer(operation, startTime, success, error) { + const endTime = Date.now(); + const duration = endTime - startTime; + this.performanceMetrics.push({ + operation, + startTime, + endTime, + duration, + success, + error, + }); + } + getPerformanceMetrics() { + return [...this.performanceMetrics]; + } + clearPerformanceMetrics() { + this.performanceMetrics = []; + } + addCreatedEventId(eventId) { + this.createdEventIds.push(eventId); + } + getCreatedEventIds() { + return [...this.createdEventIds]; + } + clearCreatedEventIds() { + this.createdEventIds = []; + } + addCreatedWorkspaceId(workspaceId) { + this.createdWorkspaceIds.push(workspaceId); + } + getCreatedWorkspaceIds() { + return [...this.createdWorkspaceIds]; + } + clearCreatedWorkspaceIds() { + this.createdWorkspaceIds = []; + } + static getSearchQueries() { + return [ + 'Test Integration', + 'meeting', + 'recurring', + 'attendees', + 'Conference Room', + 'nonexistent_query_should_return_empty', + ]; + } + static validateEventResponse(response) { + if (!response || !response.content || !Array.isArray(response.content)) { + return false; + } + const text = response.content[0]?.text; + return typeof text === 'string'; + } + static validateWorkspaceResponse(response) { + if (!response || !response.content || !Array.isArray(response.content)) { + return false; + } + const text = response.content[0]?.text; + console.log('๐Ÿš€ ~ validateWorkspaceResponse ~ text:', text); + return typeof text === 'string'; + } + static extractWorkspaceIdFromResponse(response) { + const text = response.content[0]?.text; + if (!text) + return null; + const pattern = /"id": "([a-zA-Z0-9_-]+)"/; + const match = text.match(pattern); + return match ? match[1] : null; + } + static getInvalidTestData() { + return { + invalidCalendarId: 'invalid_calendar_id', + invalidEventId: 'invalid_event_id', + invalidTimeFormat: '2024-13-45T25:99:99Z', + invalidTimezone: 'Invalid/Timezone', + invalidEmail: 'not-an-email', + invalidColorId: '999', + malformedRecurrence: ['INVALID:RRULE'], + futureDateInPast: '2020-01-01T10:00:00Z', + }; + } +} diff --git a/dist/src/tools/create_collection.js b/dist/src/tools/create_collection.js new file mode 100644 index 0000000..31e7f0d --- /dev/null +++ b/dist/src/tools/create_collection.js @@ -0,0 +1,810 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'create-collection'; +export const description = 'Creates a collection using the [Postman Collection v2.1.0 schema format](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n\n**Note:**\n\n- If you do not include the \\`workspace\\` query parameter, the system creates the collection in your "My Workspace" workspace.\n- For a complete list of available property values for this endpoint, use the following references available in the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html):\n - \\`info\\` object โ€” Refer to the **Information** entry.\n - \\`item\\` object โ€” Refer to the **Items** entry.\n- For all other possible values, refer to the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n'; +export const parameters = z.object({ + workspace: z.string().describe("The workspace's ID.").optional(), + collection: z + .object({ + info: z + .object({ + name: z.string().describe("The collection's name."), + description: z.string().describe("The collection's description.").optional(), + schema: z + .literal('https://schema.getpostman.com/json/collection/v2.1.0/collection.json') + .describe('The "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" Postman Collection Format v2.1.0 schema.'), + }) + .describe('Information about the collection.'), + item: z.array(z + .object({ + name: z.string().describe("The item's name.").optional(), + description: z.string().nullable().describe("The item's description.").optional(), + variable: z + .array(z + .object({ + key: z.string().describe("The variable's key (name).").optional(), + value: z.string().describe("The key's value.").optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + description: z + .string() + .describe("The variable's description. Doesn't apply to collection-level variables.") + .optional(), + disabled: z.boolean().default(false), + }) + .describe('Information about the variable.')) + .describe("A list of the collection's [variables](https://learning.postman.com/docs/sending-requests/variables/variables/). Make certain not to include sensitive information in variables.") + .optional(), + event: z + .array(z + .object({ + listen: z + .enum(['test', 'prerequest']) + .describe('Can be set to `test` or `prerequest` for test scripts or pre-request scripts respectively.'), + script: z + .object({ + type: z + .string() + .describe('The type of script. For example, `text/javascript`.') + .optional(), + exec: z + .array(z.string().nullable()) + .describe('A list of script strings, where each line represents a line of code. Separate lines makes it easy to track script changes.') + .optional(), + }) + .describe('Information about the Javascript code that can be used to to perform setup or teardown operations in a response.') + .optional(), + }) + .describe("Information about the collection's events.")) + .describe('A list of scripts configured to run when specific events occur.') + .optional(), + request: z + .object({ + url: z + .union([ + z.string().nullable().describe("The request's raw URL."), + z.object({ + raw: z.string().describe("The request's raw URL.").optional(), + protocol: z.string().describe('The request protocol.').optional(), + host: z.array(z.string().nullable()).describe("The host's URL.").optional(), + path: z + .array(z.string()) + .describe("A list of the URL's path components.") + .optional(), + port: z + .string() + .describe("The URL's port number. An empty value indicates port `80` (http) or `443` (https).") + .optional(), + query: z + .array(z.object({ + key: z + .string() + .nullable() + .describe("The query parameter's key.") + .optional(), + value: z.string().nullable().describe("The key's value.").optional(), + disabled: z + .boolean() + .describe("If true, the query parameter isn't sent with the request.") + .default(false), + description: z + .string() + .nullable() + .describe("The query parameter's description.") + .optional(), + })) + .describe('A list of query parameters. These are the query string parts of the URL, parsed as separate variables.') + .optional(), + }), + ]) + .describe('Information about the URL.') + .optional(), + auth: z + .object({ + type: z + .enum([ + 'noauth', + 'basic', + 'bearer', + 'apikey', + 'digest', + 'oauth1', + 'oauth2', + 'hawk', + 'awsv4', + 'ntlm', + 'edgegrid', + ]) + .describe('The authorization type.'), + noauth: z.any().optional(), + apikey: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe("The API key's authentication information.") + .optional(), + awsv4: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [AWS Signature](https://learning.postman.com/docs/sending-requests/authorization/aws-signature/) authentication.') + .optional(), + basic: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [Basic Auth](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#basic-auth).') + .optional(), + bearer: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [Bearer Token](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#bearer-token) authentication.') + .optional(), + digest: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [Digest](https://learning.postman.com/docs/sending-requests/authorization/digest-auth/) access authentication.') + .optional(), + edgegrid: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [Akamai Edgegrid](https://learning.postman.com/docs/sending-requests/authorization/akamai-edgegrid/) authentication.') + .optional(), + hawk: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [Hawk](https://learning.postman.com/docs/sending-requests/authorization/hawk-authentication/) authentication.') + .optional(), + ntlm: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [NTLM](https://learning.postman.com/docs/sending-requests/authorization/ntlm-authentication/) authentication.') + .optional(), + oauth1: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [OAuth1](https://learning.postman.com/docs/sending-requests/authorization/oauth-10/) authentication.') + .optional(), + oauth2: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [OAuth2](https://learning.postman.com/docs/sending-requests/authorization/oauth-20/) authentication.') + .optional(), + }) + .describe('The [authorization type supported by Postman](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).') + .optional(), + method: z.string().describe("The request's standard HTTP method.").optional(), + description: z + .string() + .nullable() + .describe("The request's description.") + .optional(), + header: z + .array(z + .object({ + key: z + .string() + .describe("The header's key, such as `Content-Type` or `X-Custom-Header`."), + value: z.string().describe("The header key's value."), + disabled: z + .boolean() + .describe("If true, the current header isn't sent with requests.") + .default(false), + description: z + .string() + .nullable() + .describe("The header's description.") + .optional(), + }) + .describe('Information about the header.')) + .describe('A list of headers.') + .optional(), + body: z + .object({ + mode: z + .enum(['raw', 'urlencoded', 'formdata', 'file', 'graphql']) + .describe('The data associated with the request.') + .optional(), + raw: z + .string() + .describe('If the `mode` value is `raw`, the raw content of the request body.') + .optional(), + urlencoded: z + .array(z.object({ + key: z.string().describe('The key value.'), + value: z.string().describe("The key's value.").optional(), + description: z + .string() + .nullable() + .describe("The key's description.") + .optional(), + })) + .describe('A list of x-www-form-encoded key/value pairs.') + .optional(), + formdata: z + .array(z.record(z.any()).and(z.union([ + z.object({ + key: z.string().describe('The key value.').optional(), + value: z.string().describe("The key's value.").optional(), + type: z.literal('text').describe('The `text` value.').optional(), + contentType: z + .string() + .describe('The form-data Content-Type header.') + .optional(), + description: z + .string() + .nullable() + .describe("The key's description.") + .optional(), + }), + z.object({ + key: z.string().describe('The key value.').optional(), + src: z + .any() + .superRefine((x, ctx) => { + const schemas = [z.string().nullable(), z.array(z.string())]; + const errors = schemas.reduce((errors, schema) => ((result) => result.error ? [...errors, result.error] : errors)(schema.safeParse(x)), []); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .optional(), + type: z.literal('file').describe('The `file` value.').optional(), + contentType: z + .string() + .describe('The form-data Content-Type header.') + .optional(), + description: z + .string() + .nullable() + .describe("The key's description.") + .optional(), + }), + ]))) + .describe('If the `mode` value is `formdata`, then a list of form-data key/pair values.') + .optional(), + file: z + .object({ + src: z + .string() + .nullable() + .describe('The name of the file to upload (not its path). A null value indicates that no file is selected as a part of the request body.') + .optional(), + }) + .describe('If the `mode` value is `file`, an object containing the file request information.') + .optional(), + graphql: z + .object({ + query: z.string().describe('The GraphQL query.').optional(), + variables: z + .string() + .nullable() + .describe('The GraphQL query variables, in JSON format.') + .optional(), + }) + .describe('If the `mode` value is `graphql`, an object containing the GraphQL request information.') + .optional(), + options: z + .record(z.any()) + .describe('Additional configurations and options set for various modes.') + .optional(), + }) + .describe('Information about the collection\'s request body. To set this to "none", pass an empty object.') + .optional(), + }) + .describe('Information about the collection request.') + .optional(), + protocolProfileBehavior: z + .object({ + strictSSL: z + .boolean() + .describe('If true, enables certificate verification.') + .optional(), + followRedirects: z + .boolean() + .describe('If true, follow HTTP 3xx responses as redirects.') + .optional(), + maxRedirects: z + .number() + .describe('The maximum number of redirects to follow.') + .optional(), + disableBodyPruning: z + .boolean() + .describe('If true, disables request body pruning for the GET, COPY, HEAD, PURGE, and UNLOCK methods.') + .optional(), + disableUrlEncoding: z + .boolean() + .describe('If true, disables the percent encoding of auth, path, query, and fragment URL segments.') + .optional(), + disabledSystemHeaders: z + .object({ + 'cache-control': z.boolean().optional(), + 'postman-token': z.boolean().optional(), + 'content-type': z.boolean().optional(), + 'content-length': z.boolean().optional(), + 'accept-encoding': z.boolean().optional(), + connection: z.boolean().optional(), + host: z.boolean().optional(), + }) + .describe('Disable the system headers which are added implicitly.') + .optional(), + insecureHTTPParser: z + .boolean() + .describe('If true, uses an insecure HTTP parser that accepts invalid HTTP headers.') + .optional(), + followOriginalHttpMethod: z + .boolean() + .describe('If true, redirects with the original HTTP method. Redirects with the GET HTTP method by default.') + .optional(), + followAuthorizationHeader: z + .boolean() + .describe('If true, retains the `authorization` header when a redirect happens to a different hostname.') + .optional(), + protocolVersion: z + .enum(['http1', 'http2', 'auto']) + .describe('The HTTP protocol version to use. Supports the `http1`, `http2`, and `auto` values.') + .optional(), + removeRefererHeaderOnRedirect: z + .boolean() + .describe('If true, removes the `referer` header when a redirect happens.') + .optional(), + tlsPreferServerCiphers: z + .boolean() + .describe("If true, uses the server's cipher suite order instead of the client's during negotiation.") + .optional(), + tlsDisabledProtocols: z + .array(z.string()) + .describe('The SSL and TLS protocol versions to disable during negotiation.') + .optional(), + tlsCipherSelection: z + .array(z.string()) + .describe('The order of cipher suites that the SSL server profile uses to establish a secure connection.') + .optional(), + }) + .describe('The [settings](https://learning.postman.com/docs/sending-requests/create-requests/request-settings/) used to alter the [Protocol Profile Behavior](https://github.com/postmanlabs/postman-runtime/blob/develop/docs/protocol-profile-behavior.md) of sending a request.') + .optional(), + }) + .describe('Information about the collection request or folder.')), + event: z + .array(z + .object({ + listen: z + .enum(['test', 'prerequest']) + .describe('Can be set to `test` or `prerequest` for test scripts or pre-request scripts respectively.'), + script: z + .object({ + type: z + .string() + .describe('The type of script. For example, `text/javascript`.') + .optional(), + exec: z + .array(z.string().nullable()) + .describe('A list of script strings, where each line represents a line of code. Separate lines makes it easy to track script changes.') + .optional(), + }) + .describe('Information about the Javascript code that can be used to to perform setup or teardown operations in a response.') + .optional(), + }) + .describe("Information about the collection's events.")) + .describe('A list of scripts configured to run when specific events occur.') + .optional(), + variable: z + .array(z + .object({ + key: z.string().describe("The variable's key (name).").optional(), + value: z.string().describe("The key's value.").optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + description: z + .string() + .describe("The variable's description. Doesn't apply to collection-level variables.") + .optional(), + disabled: z.boolean().default(false), + }) + .describe('Information about the variable.')) + .describe("A list of the collection's [variables](https://learning.postman.com/docs/sending-requests/variables/variables/). Make certain not to include sensitive information in variables.") + .optional(), + auth: z + .object({ + type: z + .enum([ + 'noauth', + 'basic', + 'bearer', + 'apikey', + 'digest', + 'oauth1', + 'oauth2', + 'hawk', + 'awsv4', + 'ntlm', + 'edgegrid', + ]) + .describe('The authorization type.'), + noauth: z.any().optional(), + apikey: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe("The API key's authentication information.") + .optional(), + awsv4: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [AWS Signature](https://learning.postman.com/docs/sending-requests/authorization/aws-signature/) authentication.') + .optional(), + basic: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [Basic Auth](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#basic-auth).') + .optional(), + bearer: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [Bearer Token](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#bearer-token) authentication.') + .optional(), + digest: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [Digest](https://learning.postman.com/docs/sending-requests/authorization/digest-auth/) access authentication.') + .optional(), + edgegrid: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [Akamai Edgegrid](https://learning.postman.com/docs/sending-requests/authorization/akamai-edgegrid/) authentication.') + .optional(), + hawk: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [Hawk](https://learning.postman.com/docs/sending-requests/authorization/hawk-authentication/) authentication.') + .optional(), + ntlm: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [NTLM](https://learning.postman.com/docs/sending-requests/authorization/ntlm-authentication/) authentication.') + .optional(), + oauth1: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [OAuth1](https://learning.postman.com/docs/sending-requests/authorization/oauth-10/) authentication.') + .optional(), + oauth2: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [OAuth2](https://learning.postman.com/docs/sending-requests/authorization/oauth-20/) authentication.') + .optional(), + }) + .describe('The [authorization type supported by Postman](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).') + .optional(), + protocolProfileBehavior: z + .object({ + strictSSL: z.boolean().describe('If true, enables certificate verification.').optional(), + followRedirects: z + .boolean() + .describe('If true, follow HTTP 3xx responses as redirects.') + .optional(), + maxRedirects: z + .number() + .describe('The maximum number of redirects to follow.') + .optional(), + disableBodyPruning: z + .boolean() + .describe('If true, disables request body pruning for the GET, COPY, HEAD, PURGE, and UNLOCK methods.') + .optional(), + disableUrlEncoding: z + .boolean() + .describe('If true, disables the percent encoding of auth, path, query, and fragment URL segments.') + .optional(), + disabledSystemHeaders: z + .object({ + 'cache-control': z.boolean().optional(), + 'postman-token': z.boolean().optional(), + 'content-type': z.boolean().optional(), + 'content-length': z.boolean().optional(), + 'accept-encoding': z.boolean().optional(), + connection: z.boolean().optional(), + host: z.boolean().optional(), + }) + .describe('Disable the system headers which are added implicitly.') + .optional(), + insecureHTTPParser: z + .boolean() + .describe('If true, uses an insecure HTTP parser that accepts invalid HTTP headers.') + .optional(), + followOriginalHttpMethod: z + .boolean() + .describe('If true, redirects with the original HTTP method. Redirects with the GET HTTP method by default.') + .optional(), + followAuthorizationHeader: z + .boolean() + .describe('If true, retains the `authorization` header when a redirect happens to a different hostname.') + .optional(), + protocolVersion: z + .enum(['http1', 'http2', 'auto']) + .describe('The HTTP protocol version to use. Supports the `http1`, `http2`, and `auto` values.') + .optional(), + removeRefererHeaderOnRedirect: z + .boolean() + .describe('If true, removes the `referer` header when a redirect happens.') + .optional(), + tlsPreferServerCiphers: z + .boolean() + .describe("If true, uses the server's cipher suite order instead of the client's during negotiation.") + .optional(), + tlsDisabledProtocols: z + .array(z.string()) + .describe('The SSL and TLS protocol versions to disable during negotiation.') + .optional(), + tlsCipherSelection: z + .array(z.string()) + .describe('The order of cipher suites that the SSL server profile uses to establish a secure connection.') + .optional(), + }) + .describe('The [settings](https://learning.postman.com/docs/sending-requests/create-requests/request-settings/) used to alter the [Protocol Profile Behavior](https://github.com/postmanlabs/postman-runtime/blob/develop/docs/protocol-profile-behavior.md) of sending a request.') + .optional(), + }) + .optional(), +}); +export const annotations = { + title: 'Creates a collection using the [Postman Collection v2.1.0 schema format](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n\n**Note:**\n\n- If you do not include the \\`workspace\\` query parameter, the system creates the collection in your "My Workspace" workspace.\n- For a complete list of available property values for this endpoint, use the following references available in the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html):\n - \\`info\\` object โ€” Refer to the **Information** entry.\n - \\`item\\` object โ€” Refer to the **Items** entry.\n- For all other possible values, refer to the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections`; + const query = new URLSearchParams(); + if (params.workspace !== undefined) + query.set('workspace', String(params.workspace)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.collection !== undefined) + bodyPayload.collection = params.collection; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/create_collection_comment.js b/dist/src/tools/create_collection_comment.js new file mode 100644 index 0000000..c09a536 --- /dev/null +++ b/dist/src/tools/create_collection_comment.js @@ -0,0 +1,65 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'create-collection-comment'; +export const description = 'Creates a comment on a collection. To create a reply on an existing comment, include the \\`threadId\\` property in the request body.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + body: z.string().describe('The contents of the comment.'), + threadId: z + .number() + .int() + .describe("The comment's thread ID. To create a reply on an existing comment, include this property.") + .optional(), + tags: z + .object({ + userName: z + .object({ + type: z.literal('user').describe('The `user` value.'), + id: z.string().describe("The user's ID."), + }) + .describe("An object that contains information about the tagged user. The object's name is the user's Postman username. For example, `@user-postman`.") + .optional(), + }) + .describe('Information about users tagged in the `body` comment.') + .optional(), +}); +export const annotations = { + title: 'Creates a comment on a collection. To create a reply on an existing comment, include the \\`threadId\\` property in the request body.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/comments`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.body !== undefined) + bodyPayload.body = params.body; + if (params.threadId !== undefined) + bodyPayload.threadId = params.threadId; + if (params.tags !== undefined) + bodyPayload.tags = params.tags; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/create_collection_folder.js b/dist/src/tools/create_collection_folder.js new file mode 100644 index 0000000..09f7729 --- /dev/null +++ b/dist/src/tools/create_collection_folder.js @@ -0,0 +1,50 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'create-collection-folder'; +export const description = 'Creates a folder in a collection. For a complete list of properties, refer to the **Folder** entry in the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n\nYou can use this endpoint to to import requests and responses into a newly-created folder. To do this, include the \\`requests\\` field and the list of request objects in the request body. For more information, see the provided example.\n\n**Note:**\n\nIt is recommended that you pass the \\`name\\` property in the request body. If you do not, the system uses a null value. As a result, this creates a folder with a blank name.\n'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's ID."), + name: z + .string() + .describe("The folder's name. It is recommended that you pass the `name` property in the request body. If you do not, the system uses a null value. As a result, this creates a folder with a blank name.") + .optional(), + folder: z.string().describe('The ID of a folder in which to create the folder.').optional(), +}); +export const annotations = { + title: 'Creates a folder in a collection. For a complete list of properties, refer to the **Folder** entry in the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n\nYou can use this endpoint to to import requests and responses into a newly-created folder. To do this, include the \\`requests\\` field and the list of request objects in the request body. For more information, see the provided example.\n\n**Note:**\n\nIt is recommended that you pass the \\`name\\` property in the request body. If you do not, the system uses a null value. As a result, this creates a folder with a blank name.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/folders`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.name !== undefined) + bodyPayload.name = params.name; + if (params.folder !== undefined) + bodyPayload.folder = params.folder; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/create_collection_fork.js b/dist/src/tools/create_collection_fork.js new file mode 100644 index 0000000..249f1f7 --- /dev/null +++ b/dist/src/tools/create_collection_fork.js @@ -0,0 +1,47 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'create-collection-fork'; +export const description = 'Creates a [fork](https://learning.postman.com/docs/collaborating-in-postman/version-control/#creating-a-fork) from an existing collection into a workspace.'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's ID."), + workspace: z.string().describe('The workspace ID in which to create the fork.'), + label: z.string().describe("The fork's label."), +}); +export const annotations = { + title: 'Creates a [fork](https://learning.postman.com/docs/collaborating-in-postman/version-control/#creating-a-fork) from an existing collection into a workspace.', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/fork/${params.collectionId}`; + const query = new URLSearchParams(); + if (params.workspace !== undefined) + query.set('workspace', String(params.workspace)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.label !== undefined) + bodyPayload.label = params.label; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/create_collection_request.js b/dist/src/tools/create_collection_request.js new file mode 100644 index 0000000..71c0004 --- /dev/null +++ b/dist/src/tools/create_collection_request.js @@ -0,0 +1,53 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'create-collection-request'; +export const description = 'Creates a request in a collection. For a complete list of properties, refer to the **Request** entry in the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n\n**Note:**\n\nIt is recommended that you pass the \\`name\\` property in the request body. If you do not, the system uses a null value. As a result, this creates a request with a blank name.\n'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's ID."), + folderId: z + .string() + .describe('The folder ID in which to create the request. By default, the system will create the request at the collection level.') + .optional(), + name: z + .string() + .describe("The request's name. It is recommended that you pass the `name` property in the request body. If you do not, the system uses a null value. As a result, this creates a request with a blank name.") + .optional(), +}); +export const annotations = { + title: 'Creates a request in a collection. For a complete list of properties, refer to the **Request** entry in the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n\n**Note:**\n\nIt is recommended that you pass the \\`name\\` property in the request body. If you do not, the system uses a null value. As a result, this creates a request with a blank name.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/requests`; + const query = new URLSearchParams(); + if (params.folderId !== undefined) + query.set('folderId', String(params.folderId)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.name !== undefined) + bodyPayload.name = params.name; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/create_collection_response.js b/dist/src/tools/create_collection_response.js new file mode 100644 index 0000000..ec78ccb --- /dev/null +++ b/dist/src/tools/create_collection_response.js @@ -0,0 +1,50 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'create-collection-response'; +export const description = 'Creates a request response in a collection. For a complete list of request body properties, refer to the **Response** entry in the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n\n**Note:**\n\nIt is recommended that you pass the \\`name\\` property in the request body. If you do not, the system uses a null value. As a result, this creates a response with a blank name.\n'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's ID."), + requestId: z.string().describe("The parent request's ID."), + name: z + .string() + .describe("The response's name. It is recommended that you pass the `name` property in the request body. If you do not, the system uses a null value. As a result, this creates a response with a blank name.") + .optional(), +}); +export const annotations = { + title: 'Creates a request response in a collection. For a complete list of request body properties, refer to the **Response** entry in the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n\n**Note:**\n\nIt is recommended that you pass the \\`name\\` property in the request body. If you do not, the system uses a null value. As a result, this creates a response with a blank name.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/responses`; + const query = new URLSearchParams(); + if (params.requestId !== undefined) + query.set('requestId', String(params.requestId)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.name !== undefined) + bodyPayload.name = params.name; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/create_environment.js b/dist/src/tools/create_environment.js new file mode 100644 index 0000000..11f8f56 --- /dev/null +++ b/dist/src/tools/create_environment.js @@ -0,0 +1,59 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'create-environment'; +export const description = 'Creates an environment.\n\n**Note:**\n\n- The request body size cannot exceed the maximum allowed size of 30MB.\n- If you receive an HTTP \\`411 Length Required\\` error response, manually pass the \\`Content-Length\\` header and its value in the request header.\n- If you do not include the \\`workspace\\` query parameter, the system creates the collection in your "My Workspace" workspace.\n'; +export const parameters = z.object({ + workspace: z.string().describe("The workspace's ID.").optional(), + environment: z + .object({ + name: z.string().describe("The environment's name."), + values: z + .array(z.object({ + enabled: z.boolean().describe('If true, the variable is enabled.').optional(), + key: z.string().describe("The variable's name.").optional(), + value: z.string().describe("The variable's value.").optional(), + type: z.enum(['secret', 'default']).describe('The variable type.').optional(), + })) + .describe("Information about the environment's variables.") + .optional(), + }) + .optional(), +}); +export const annotations = { + title: 'Creates an environment.\n\n**Note:**\n\n- The request body size cannot exceed the maximum allowed size of 30MB.\n- If you receive an HTTP \\`411 Length Required\\` error response, manually pass the \\`Content-Length\\` header and its value in the request header.\n- If you do not include the \\`workspace\\` query parameter, the system creates the collection in your "My Workspace" workspace.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; +export async function handler(params, extra) { + try { + const endpoint = `/environments`; + const query = new URLSearchParams(); + if (params.workspace !== undefined) + query.set('workspace', String(params.workspace)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.environment !== undefined) + bodyPayload.environment = params.environment; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/create_folder_comment.js b/dist/src/tools/create_folder_comment.js new file mode 100644 index 0000000..b525f17 --- /dev/null +++ b/dist/src/tools/create_folder_comment.js @@ -0,0 +1,66 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'create-folder-comment'; +export const description = 'Creates a comment on a folder. To create a reply on an existing comment, include the \\`threadId\\` property in the request body.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + folderId: z.string().describe("The folder's unique ID."), + body: z.string().describe('The contents of the comment.'), + threadId: z + .number() + .int() + .describe("The comment's thread ID. To create a reply on an existing comment, include this property.") + .optional(), + tags: z + .object({ + userName: z + .object({ + type: z.literal('user').describe('The `user` value.'), + id: z.string().describe("The user's ID."), + }) + .describe("An object that contains information about the tagged user. The object's name is the user's Postman username. For example, `@user-postman`.") + .optional(), + }) + .describe('Information about users tagged in the `body` comment.') + .optional(), +}); +export const annotations = { + title: 'Creates a comment on a folder. To create a reply on an existing comment, include the \\`threadId\\` property in the request body.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/folders/${params.folderId}/comments`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.body !== undefined) + bodyPayload.body = params.body; + if (params.threadId !== undefined) + bodyPayload.threadId = params.threadId; + if (params.tags !== undefined) + bodyPayload.tags = params.tags; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/create_mock.js b/dist/src/tools/create_mock.js new file mode 100644 index 0000000..5f5b06e --- /dev/null +++ b/dist/src/tools/create_mock.js @@ -0,0 +1,59 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'create-mock'; +export const description = 'Creates a mock server in a collection.\n\n**Note:**\n\n- If you do not include the \\`workspaceId\\` query parameter, the system creates the mock server in your [Personal\nworkspace](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/creating-workspaces/).\n- You cannot create mocks for collections added to an API definition.\n'; +export const parameters = z.object({ + workspaceId: z.string().describe("The workspace's ID.").optional(), + mock: z + .object({ + collection: z.string().describe("The unique ID of the mock's associated collection."), + environment: z + .string() + .describe("The unique ID of the mock's associated environment.") + .optional(), + name: z.string().describe("The mock server's name.").optional(), + private: z + .boolean() + .describe('If true, the mock server is set private. By default, mock servers are public and can receive requests from anyone and anywhere.') + .default(false), + }) + .optional(), +}); +export const annotations = { + title: 'Creates a mock server in a collection.\n\n**Note:**\n\n- If you do not include the \\`workspaceId\\` query parameter, the system creates the mock server in your [Personal\nworkspace](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/creating-workspaces/).\n- You cannot create mocks for collections added to an API definition.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; +export async function handler(params, extra) { + try { + const endpoint = `/mocks`; + const query = new URLSearchParams(); + if (params.workspaceId !== undefined) + query.set('workspaceId', String(params.workspaceId)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.mock !== undefined) + bodyPayload.mock = params.mock; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/create_monitor.js b/dist/src/tools/create_monitor.js new file mode 100644 index 0000000..805225e --- /dev/null +++ b/dist/src/tools/create_monitor.js @@ -0,0 +1,148 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'create-monitor'; +export const description = 'Creates a monitor.\n\n**Note:**\n\n- You cannot create monitors for collections added to an API definition.\n- If you do not pass the \\`workspace\\` parameter, the monitor is created in your personal workspace.\n'; +export const parameters = z.object({ + workspace: z.string().describe("The workspace's ID.").optional(), + monitor: z + .object({ + name: z.string().describe("The monitor's name."), + active: z + .boolean() + .describe('If true, the monitor is active and makes calls to the specified URL.') + .default(true), + notificationLimit: z + .number() + .gte(1) + .lte(99) + .describe('Stop email notifications after the given number consecutive failures.') + .optional(), + collection: z.string().describe("The unique ID of the monitor's associated collection."), + environment: z + .string() + .describe("The unique ID of the monitor's associated environment.") + .optional(), + retry: z + .object({ + attempts: z + .number() + .gte(1) + .lte(2) + .describe('The number of times to reattempt a monitor run if it fails or errors. This may impact your [monitor usage](https://learning.postman.com/docs/monitoring-your-api/monitor-usage/#view-monitor-usage).') + .optional(), + }) + .optional(), + options: z + .object({ + followRedirects: z.boolean().describe('If true, follow redirects enabled.').optional(), + requestDelay: z + .number() + .gte(1) + .lte(900000) + .describe("The monitor's request delay value, in milliseconds.") + .optional(), + requestTimeout: z + .number() + .gte(1) + .lte(900000) + .describe("The monitor's request timeout value, in milliseconds.") + .optional(), + strictSSL: z.boolean().describe('If true, strict SSL enabled.').optional(), + }) + .describe("Information about the monitor's option settings.") + .optional(), + schedule: z + .object({ + cron: z + .string() + .describe('The cron expression that defines when the monitor runs. Use standard five-field POSIX cron syntax.\n') + .optional(), + timezone: z + .string() + .describe("The monitor's [timezone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones).") + .optional(), + }) + .describe("Information about the monitor's schedule."), + distribution: z + .array(z.object({ + region: z + .enum([ + 'us-east', + 'us-west', + 'ap-southeast', + 'ca-central', + 'eu-central', + 'sa-east', + 'uk', + 'us-east-staticip', + 'us-west-staticip', + ]) + .describe('The assigned distribution region.') + .optional(), + })) + .describe("A list of the monitor's [geographic regions](https://learning.postman.com/docs/monitoring-your-api/setting-up-monitor/#add-regions).") + .optional(), + notifications: z + .object({ + onError: z + .array(z.object({ + email: z + .string() + .email() + .describe('The email address of the user to notify on monitor error.') + .optional(), + })) + .optional(), + onFailure: z + .array(z.object({ + email: z + .string() + .email() + .describe('The email address of the user to notify on monitor failure.') + .optional(), + })) + .optional(), + }) + .describe("Information about the monitor's notification settings.") + .optional(), + }) + .optional(), +}); +export const annotations = { + title: 'Creates a monitor.\n\n**Note:**\n\n- You cannot create monitors for collections added to an API definition.\n- If you do not pass the \\`workspace\\` parameter, the monitor is created in your personal workspace.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; +export async function handler(params, extra) { + try { + const endpoint = `/monitors`; + const query = new URLSearchParams(); + if (params.workspace !== undefined) + query.set('workspace', String(params.workspace)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.monitor !== undefined) + bodyPayload.monitor = params.monitor; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/create_request_comment.js b/dist/src/tools/create_request_comment.js new file mode 100644 index 0000000..85cc427 --- /dev/null +++ b/dist/src/tools/create_request_comment.js @@ -0,0 +1,68 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'create-request-comment'; +export const description = "The request ID must contain the team ID as a prefix, in \\`teamId-requestId\\` format.\n\nFor example, if you're creating a comment on collection ID \\`24585957-7b2c98f7-30db-4b67-8685-0079f48a0947\\` (note on the prefix), and\nthe collection request's ID is \\`2c450b59-9bbf-729b-6ac0-f92535a7c336\\`, then the \\`{requestId}\\` must be \\`24585957-2c450b59-9bbf-729b-6ac0-f92535a7c336\\`.\n"; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + requestId: z + .string() + .describe("The request ID must contain the team ID as a prefix, in `teamId-requestId` format.\n\nFor example, if you're creating a comment on collection ID `24585957-7b2c98f7-30db-4b67-8685-0079f48a0947` (note on the prefix), and\nthe collection request's ID is `2c450b59-9bbf-729b-6ac0-f92535a7c336`, then the `{requestId}` must be `24585957-2c450b59-9bbf-729b-6ac0-f92535a7c336`.\n"), + body: z.string().describe('The contents of the comment.'), + threadId: z + .number() + .int() + .describe("The comment's thread ID. To create a reply on an existing comment, include this property.") + .optional(), + tags: z + .object({ + userName: z + .object({ + type: z.literal('user').describe('The `user` value.'), + id: z.string().describe("The user's ID."), + }) + .describe("An object that contains information about the tagged user. The object's name is the user's Postman username. For example, `@user-postman`.") + .optional(), + }) + .describe('Information about users tagged in the `body` comment.') + .optional(), +}); +export const annotations = { + title: "The request ID must contain the team ID as a prefix, in \\`teamId-requestId\\` format.\n\nFor example, if you're creating a comment on collection ID \\`24585957-7b2c98f7-30db-4b67-8685-0079f48a0947\\` (note on the prefix), and\nthe collection request's ID is \\`2c450b59-9bbf-729b-6ac0-f92535a7c336\\`, then the \\`{requestId}\\` must be \\`24585957-2c450b59-9bbf-729b-6ac0-f92535a7c336\\`.\n", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/requests/${params.requestId}/comments`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.body !== undefined) + bodyPayload.body = params.body; + if (params.threadId !== undefined) + bodyPayload.threadId = params.threadId; + if (params.tags !== undefined) + bodyPayload.tags = params.tags; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/create_response_comment.js b/dist/src/tools/create_response_comment.js new file mode 100644 index 0000000..f14ff00 --- /dev/null +++ b/dist/src/tools/create_response_comment.js @@ -0,0 +1,66 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'create-response-comment'; +export const description = 'Creates a comment on a response. To create a reply on an existing comment, include the \\`threadId\\` property in the request body.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + responseId: z.string().describe("The response's unique ID."), + body: z.string().describe('The contents of the comment.'), + threadId: z + .number() + .int() + .describe("The comment's thread ID. To create a reply on an existing comment, include this property.") + .optional(), + tags: z + .object({ + userName: z + .object({ + type: z.literal('user').describe('The `user` value.'), + id: z.string().describe("The user's ID."), + }) + .describe("An object that contains information about the tagged user. The object's name is the user's Postman username. For example, `@user-postman`.") + .optional(), + }) + .describe('Information about users tagged in the `body` comment.') + .optional(), +}); +export const annotations = { + title: 'Creates a comment on a response. To create a reply on an existing comment, include the \\`threadId\\` property in the request body.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/responses/${params.responseId}/comments`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.body !== undefined) + bodyPayload.body = params.body; + if (params.threadId !== undefined) + bodyPayload.threadId = params.threadId; + if (params.tags !== undefined) + bodyPayload.tags = params.tags; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/create_spec.js b/dist/src/tools/create_spec.js new file mode 100644 index 0000000..dd7811f --- /dev/null +++ b/dist/src/tools/create_spec.js @@ -0,0 +1,59 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'create-spec'; +export const description = "Creates an API specification in Postman's [Spec Hub](https://learning.postman.com/docs/design-apis/specifications/overview/).\n\n**Note:**\n- Postman supports OpenAPI 3.0 and AsyncAPI 2.0 specifications.\n- This endpoint does not yet support multiple files.\n"; +export const parameters = z.object({ + workspaceId: z.string().describe("The workspace's ID."), + name: z.string().describe("The specification's name."), + type: z.enum(['OPENAPI:3.0', 'ASYNCAPI:2.0']).describe("The specification's type."), + files: z + .array(z.object({ + path: z + .string() + .describe("The file's path. Accepts the `index.json` or `index.yaml` value."), + content: z.string().describe("The file's stringified contents."), + })) + .describe("A list of the specification's files and their contents."), +}); +export const annotations = { + title: "Creates an API specification in Postman's [Spec Hub](https://learning.postman.com/docs/design-apis/specifications/overview/).\n\n**Note:**\n- Postman supports OpenAPI 3.0 and AsyncAPI 2.0 specifications.\n- This endpoint does not yet support multiple files.\n", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; +export async function handler(params, extra) { + try { + const endpoint = `/specs`; + const query = new URLSearchParams(); + if (params.workspaceId !== undefined) + query.set('workspaceId', String(params.workspaceId)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.name !== undefined) + bodyPayload.name = params.name; + if (params.type !== undefined) + bodyPayload.type = params.type; + if (params.files !== undefined) + bodyPayload.files = params.files; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/create_update_spec_file.js b/dist/src/tools/create_update_spec_file.js new file mode 100644 index 0000000..eae8593 --- /dev/null +++ b/dist/src/tools/create_update_spec_file.js @@ -0,0 +1,45 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'create-update-spec-file'; +export const description = "Creates or updates an API specification's file.\n"; +export const parameters = z.object({ + specId: z.string().describe("The spec's ID."), + filePath: z.string().describe('The path to the file.'), + content: z.string().describe("The specification's stringified contents."), +}); +export const annotations = { + title: "Creates or updates an API specification's file.\n", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/specs/${params.specId}/files/${params.filePath}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.content !== undefined) + bodyPayload.content = params.content; + const result = await fetchPostmanAPI(url, { + method: 'PATCH', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/create_workspace.js b/dist/src/tools/create_workspace.js new file mode 100644 index 0000000..066637b --- /dev/null +++ b/dist/src/tools/create_workspace.js @@ -0,0 +1,53 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'create-workspace'; +export const description = 'Creates a new [workspace](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/creating-workspaces/).\n\n**Note:**\n\n- This endpoint returns a 403 \\`Forbidden\\` response if the user does not have permission to create workspaces. [Admins and Super Admins](https://learning.postman.com/docs/collaborating-in-postman/roles-and-permissions/#team-roles) can configure workspace permissions to restrict users and/or user groups from creating workspaces or require approvals for the creation of team workspaces.\n- There are rate limits when publishing public workspaces.\n- Public team workspace names must be unique.\n\n### Important\n\nWe deprecated linking collections or environments between workspaces. We do not recommend that you do this.\n\nIf you have a linked collection or environment, note the following:\n- The endpoint does not create a clone of a collection or environment.\n- Any changes you make to a linked collection or environment changes them in all workspaces.\n- If you delete a collection or environment linked between workspaces, the system deletes it in all the workspaces.\n'; +export const parameters = z.object({ + workspace: z + .object({ + name: z.string().describe("The workspace's name."), + type: z + .enum(['personal', 'private', 'public', 'team', 'partner']) + .describe('The type of workspace:\n- `personal`\n- `private` โ€” Private workspaces are available on Postman [**Professional** and **Enterprise** plans](https://www.postman.com/pricing).\n- `public`\n- `team`\n- `partner` โ€” [Partner Workspaces](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/partner-workspaces/) are available on Postman [**Professional** and **Enterprise** plans](https://www.postman.com/pricing)).\n'), + description: z.string().describe("The workspace's description.").optional(), + about: z.string().describe('A brief summary about the workspace.').optional(), + }) + .describe('Information about the workspace.') + .optional(), +}); +export const annotations = { + title: 'Creates a new [workspace](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/creating-workspaces/).\n\n**Note:**\n\n- This endpoint returns a 403 \\`Forbidden\\` response if the user does not have permission to create workspaces. [Admins and Super Admins](https://learning.postman.com/docs/collaborating-in-postman/roles-and-permissions/#team-roles) can configure workspace permissions to restrict users and/or user groups from creating workspaces or require approvals for the creation of team workspaces.\n- There are rate limits when publishing public workspaces.\n- Public team workspace names must be unique.\n\n### Important\n\nWe deprecated linking collections or environments between workspaces. We do not recommend that you do this.\n\nIf you have a linked collection or environment, note the following:\n- The endpoint does not create a clone of a collection or environment.\n- Any changes you make to a linked collection or environment changes them in all workspaces.\n- If you delete a collection or environment linked between workspaces, the system deletes it in all the workspaces.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; +export async function handler(params, extra) { + try { + const endpoint = `/workspaces`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.workspace !== undefined) + bodyPayload.workspace = params.workspace; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/delete_api_collection_comment.js b/dist/src/tools/delete_api_collection_comment.js new file mode 100644 index 0000000..71ad554 --- /dev/null +++ b/dist/src/tools/delete_api_collection_comment.js @@ -0,0 +1,40 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'delete-api-collection-comment'; +export const description = "Deletes a comment from an API's collection. On success, this returns an HTTP \\`204 No Content\\` response.\n\n**Note:**\n\nDeleting the first comment of a thread deletes all the comments in the thread.\n"; +export const parameters = z.object({ + apiId: z.string().describe("The API's ID."), + collectionId: z.string().describe("The collection's unique ID."), + commentId: z.number().int().describe("The comment's ID."), +}); +export const annotations = { + title: "Deletes a comment from an API's collection. On success, this returns an HTTP \\`204 No Content\\` response.\n\n**Note:**\n\nDeleting the first comment of a thread deletes all the comments in the thread.\n", + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/apis/${params.apiId}/collections/${params.collectionId}/comments/${params.commentId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/delete_collection.js b/dist/src/tools/delete_collection.js new file mode 100644 index 0000000..2da2912 --- /dev/null +++ b/dist/src/tools/delete_collection.js @@ -0,0 +1,40 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'delete-collection'; +export const description = 'Deletes a collection.'; +export const parameters = z.object({ + collectionId: z + .string() + .describe('The collection ID must be in the form - (e.g. 12345-33823532ab9e41c9b6fd12d0fd459b8b).'), +}); +export const annotations = { + title: 'Deletes a collection.', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/delete_collection_comment.js b/dist/src/tools/delete_collection_comment.js new file mode 100644 index 0000000..01a7276 --- /dev/null +++ b/dist/src/tools/delete_collection_comment.js @@ -0,0 +1,39 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'delete-collection-comment'; +export const description = 'Deletes a comment from a collection. On success, this returns an HTTP \\`204 No Content\\` response.\n\n**Note:**\n\nDeleting the first comment of a thread deletes all the comments in the thread.\n'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + commentId: z.number().int().describe("The comment's ID."), +}); +export const annotations = { + title: 'Deletes a comment from a collection. On success, this returns an HTTP \\`204 No Content\\` response.\n\n**Note:**\n\nDeleting the first comment of a thread deletes all the comments in the thread.\n', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/comments/${params.commentId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/delete_collection_folder.js b/dist/src/tools/delete_collection_folder.js new file mode 100644 index 0000000..21fc786 --- /dev/null +++ b/dist/src/tools/delete_collection_folder.js @@ -0,0 +1,39 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'delete-collection-folder'; +export const description = 'Deletes a folder in a collection.'; +export const parameters = z.object({ + folderId: z.string().describe("The folder's ID."), + collectionId: z.string().describe("The collection's ID."), +}); +export const annotations = { + title: 'Deletes a folder in a collection.', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/folders/${params.folderId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/delete_collection_request.js b/dist/src/tools/delete_collection_request.js new file mode 100644 index 0000000..bba5b01 --- /dev/null +++ b/dist/src/tools/delete_collection_request.js @@ -0,0 +1,39 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'delete-collection-request'; +export const description = 'Deletes a request in a collection.'; +export const parameters = z.object({ + requestId: z.string().describe("The request's ID."), + collectionId: z.string().describe("The collection's ID."), +}); +export const annotations = { + title: 'Deletes a request in a collection.', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/requests/${params.requestId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/delete_collection_response.js b/dist/src/tools/delete_collection_response.js new file mode 100644 index 0000000..c22998e --- /dev/null +++ b/dist/src/tools/delete_collection_response.js @@ -0,0 +1,39 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'delete-collection-response'; +export const description = 'Deletes a response in a collection.'; +export const parameters = z.object({ + responseId: z.string().describe("The response's ID."), + collectionId: z.string().describe("The collection's ID."), +}); +export const annotations = { + title: 'Deletes a response in a collection.', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/responses/${params.responseId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/delete_environment.js b/dist/src/tools/delete_environment.js new file mode 100644 index 0000000..e28dc18 --- /dev/null +++ b/dist/src/tools/delete_environment.js @@ -0,0 +1,36 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'delete-environment'; +export const description = 'Deletes an environment.'; +export const parameters = z.object({ environmentId: z.string().describe("The environment's ID.") }); +export const annotations = { + title: 'Deletes an environment.', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/environments/${params.environmentId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/delete_folder_comment.js b/dist/src/tools/delete_folder_comment.js new file mode 100644 index 0000000..3b7e34b --- /dev/null +++ b/dist/src/tools/delete_folder_comment.js @@ -0,0 +1,40 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'delete-folder-comment'; +export const description = 'Deletes a comment from a folder. On success, this returns an HTTP \\`204 No Content\\` response.\n\n**Note:**\n\nDeleting the first comment of a thread deletes all the comments in the thread.\n'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + folderId: z.string().describe("The folder's unique ID."), + commentId: z.number().int().describe("The comment's ID."), +}); +export const annotations = { + title: 'Deletes a comment from a folder. On success, this returns an HTTP \\`204 No Content\\` response.\n\n**Note:**\n\nDeleting the first comment of a thread deletes all the comments in the thread.\n', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/folders/${params.folderId}/comments/${params.commentId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/delete_mock.js b/dist/src/tools/delete_mock.js new file mode 100644 index 0000000..72a58d7 --- /dev/null +++ b/dist/src/tools/delete_mock.js @@ -0,0 +1,36 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'delete-mock'; +export const description = 'Deletes a mock server.'; +export const parameters = z.object({ mockId: z.string().describe("The mock's ID.") }); +export const annotations = { + title: 'Deletes a mock server.', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/mocks/${params.mockId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/delete_monitor.js b/dist/src/tools/delete_monitor.js new file mode 100644 index 0000000..f57033c --- /dev/null +++ b/dist/src/tools/delete_monitor.js @@ -0,0 +1,36 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'delete-monitor'; +export const description = 'Deletes a monitor.'; +export const parameters = z.object({ monitorId: z.string().describe("The monitor's ID.") }); +export const annotations = { + title: 'Deletes a monitor.', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/monitors/${params.monitorId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/delete_pan_element_or_folder.js b/dist/src/tools/delete_pan_element_or_folder.js new file mode 100644 index 0000000..516b9d6 --- /dev/null +++ b/dist/src/tools/delete_pan_element_or_folder.js @@ -0,0 +1,41 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'delete-pan-element-or-folder'; +export const description = "Removes an element or delete a folder from your team's [Private API Network](https://learning.postman.com/docs/collaborating-in-postman/adding-private-network/).\n\n**Note:**\n\nRemoving an API, collection, or workspace element does not delete it. It only removes it from the Private API Network folder.\n"; +export const parameters = z.object({ + elementId: z + .string() + .describe("The element's ID or UUID. For Postman Collections you must pass the collection's UID (`userId`-`collectionId`) value."), + elementType: z.enum(['api', 'folder', 'collection', 'workspace']).describe('The element type.'), +}); +export const annotations = { + title: "Removes an element or delete a folder from your team's [Private API Network](https://learning.postman.com/docs/collaborating-in-postman/adding-private-network/).\n\n**Note:**\n\nRemoving an API, collection, or workspace element does not delete it. It only removes it from the Private API Network folder.\n", + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/network/private/${params.elementType}/${params.elementId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/delete_request_comment.js b/dist/src/tools/delete_request_comment.js new file mode 100644 index 0000000..dd98b2a --- /dev/null +++ b/dist/src/tools/delete_request_comment.js @@ -0,0 +1,40 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'delete-request-comment'; +export const description = 'Deletes a comment from a request. On success, this returns an HTTP \\`204 No Content\\` response.\n\n**Note:**\n\nDeleting the first comment of a thread deletes all the comments in the thread.\n'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + requestId: z.string().describe("The request's unique ID."), + commentId: z.number().int().describe("The comment's ID."), +}); +export const annotations = { + title: 'Deletes a comment from a request. On success, this returns an HTTP \\`204 No Content\\` response.\n\n**Note:**\n\nDeleting the first comment of a thread deletes all the comments in the thread.\n', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/requests/${params.requestId}/comments/${params.commentId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/delete_response_comment.js b/dist/src/tools/delete_response_comment.js new file mode 100644 index 0000000..a67b029 --- /dev/null +++ b/dist/src/tools/delete_response_comment.js @@ -0,0 +1,40 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'delete-response-comment'; +export const description = 'Deletes a comment from a response. On success, this returns an HTTP \\`204 No Content\\` response.\n\n**Note:**\n\nDeleting the first comment of a thread deletes all the comments in the thread.\n'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + responseId: z.string().describe("The response's unique ID."), + commentId: z.number().int().describe("The comment's ID."), +}); +export const annotations = { + title: 'Deletes a comment from a response. On success, this returns an HTTP \\`204 No Content\\` response.\n\n**Note:**\n\nDeleting the first comment of a thread deletes all the comments in the thread.\n', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/responses/${params.responseId}/comments/${params.commentId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/delete_spec.js b/dist/src/tools/delete_spec.js new file mode 100644 index 0000000..09d2a3e --- /dev/null +++ b/dist/src/tools/delete_spec.js @@ -0,0 +1,36 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'delete-spec'; +export const description = 'Deletes an API specification. On success, this returns an HTTP \\`204 No Content\\` response.'; +export const parameters = z.object({ specId: z.string().describe("The spec's ID.") }); +export const annotations = { + title: 'Deletes an API specification. On success, this returns an HTTP \\`204 No Content\\` response.', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/specs/${params.specId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/delete_workspace.js b/dist/src/tools/delete_workspace.js new file mode 100644 index 0000000..c25a483 --- /dev/null +++ b/dist/src/tools/delete_workspace.js @@ -0,0 +1,36 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'delete-workspace'; +export const description = 'Deletes an existing workspace.\n\n### Important\n\nIf you delete a workspace that has a linked collection or environment with another workspace, this will delete the collection and environment in all workspaces.\n'; +export const parameters = z.object({ workspaceId: z.string().describe("The workspace's ID.") }); +export const annotations = { + title: 'Deletes an existing workspace.\n\n### Important\n\nIf you delete a workspace that has a linked collection or environment with another workspace, this will delete the collection and environment in all workspaces.\n', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/workspaces/${params.workspaceId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/duplicate_collection.js b/dist/src/tools/duplicate_collection.js new file mode 100644 index 0000000..ced1f03 --- /dev/null +++ b/dist/src/tools/duplicate_collection.js @@ -0,0 +1,50 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'duplicate-collection'; +export const description = "Creates a duplicate of the given collection in another workspace.\n\nUse the GET \\`/collection-duplicate-tasks/{taskId}\\` endpoint to get the duplication task's current status.\n"; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + workspace: z.string().describe('The workspace ID in which to duplicate the collection.'), + suffix: z + .string() + .describe("An optional suffix to append to the duplicated collection's name.") + .optional(), +}); +export const annotations = { + title: "Creates a duplicate of the given collection in another workspace.\n\nUse the GET \\`/collection-duplicate-tasks/{taskId}\\` endpoint to get the duplication task's current status.\n", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/duplicates`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.workspace !== undefined) + bodyPayload.workspace = params.workspace; + if (params.suffix !== undefined) + bodyPayload.suffix = params.suffix; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/generate_collection.js b/dist/src/tools/generate_collection.js new file mode 100644 index 0000000..dca52ed --- /dev/null +++ b/dist/src/tools/generate_collection.js @@ -0,0 +1,88 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'generate-collection'; +export const description = 'Creates a collection from the given API specification. The response contains a polling link to the task status.'; +export const parameters = z.object({ + specId: z.string().describe("The spec's ID."), + elementType: z.literal('collection').describe('The `collection` element type.'), + name: z.string().describe("The generated collection's name.").optional(), + options: z + .object({ + requestNameSource: z + .enum(['Fallback', 'URL']) + .describe("Determines how the generated collection's requests are named. If the `Fallback` value is passed, then the request is named after one of the following values in the schema:\n- `summary`\n- `operationId`\n- `description`\n- `url`\n") + .default('Fallback'), + indentCharacter: z + .enum(['Tab', 'Space']) + .describe('The option for setting the indentation character type.') + .default('Space'), + parametersResolution: z + .enum(['Schema', 'Example']) + .describe("Whether to generate the request and response parameters based on the specification or the specification's examples.") + .default('Schema'), + folderStrategy: z + .enum(['Paths', 'Tags']) + .describe("Whether to create folders based on the specification's `paths` or `tags` properties.") + .default('Paths'), + includeAuthInfoInExample: z + .boolean() + .describe('If true, include the authentication parameters in the example request.') + .default(true), + enableOptionalParameters: z + .boolean() + .describe('If true, enables optional parameters in the collection and its requests.') + .default(true), + keepImplicitHeaders: z + .boolean() + .describe('If true, keep the implicit headers from the OpenAPI specification, which are removed by default.') + .default(false), + includeDeprecated: z + .boolean() + .describe('If true, includes all deprecated operations, parameters, and properties in generated collection.') + .default(true), + alwaysInheritAuthentication: z + .boolean() + .describe('Whether authentication details should be included in all requests, or always inherited from the collection.') + .default(false), + }) + .describe("The advanced creation options and their values. For more details, see Postman's [OpenAPI to Postman Collection Converter OPTIONS documentation](https://github.com/postmanlabs/openapi-to-postman/blob/develop/OPTIONS.md). These properties are case-sensitive.") + .optional(), +}); +export const annotations = { + title: 'Creates a collection from the given API specification. The response contains a polling link to the task status.', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; +export async function handler(params, extra) { + try { + const endpoint = `/specs/${params.specId}/generations/${params.elementType}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.name !== undefined) + bodyPayload.name = params.name; + if (params.options !== undefined) + bodyPayload.options = params.options; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/generate_spec_from_collection.js b/dist/src/tools/generate_spec_from_collection.js new file mode 100644 index 0000000..24f14d9 --- /dev/null +++ b/dist/src/tools/generate_spec_from_collection.js @@ -0,0 +1,51 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'generate-spec-from-collection'; +export const description = 'Generates an API specification for the given collection. The response contains a polling link to the task status.'; +export const parameters = z.object({ + collectionUid: z.string().describe("The collection's unique ID."), + elementType: z.literal('spec').describe('The `spec` value.'), + name: z.string().describe("The API specification's name.").optional(), + type: z.literal('OPENAPI:3.0').describe("The specification's type.").optional(), + format: z.enum(['JSON', 'YAML']).describe('The format of the API specification.').optional(), +}); +export const annotations = { + title: 'Generates an API specification for the given collection. The response contains a polling link to the task status.', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionUid}/generations/${params.elementType}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.name !== undefined) + bodyPayload.name = params.name; + if (params.type !== undefined) + bodyPayload.type = params.type; + if (params.format !== undefined) + bodyPayload.format = params.format; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_all_elements_and_folders.js b/dist/src/tools/get_all_elements_and_folders.js new file mode 100644 index 0000000..e8e5b12 --- /dev/null +++ b/dist/src/tools/get_all_elements_and_folders.js @@ -0,0 +1,122 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-all-elements-and-folders'; +export const description = "Gets information about the folders and their elements added to your team's [Private API Network](https://learning.postman.com/docs/collaborating-in-postman/adding-private-network/).\n\n**Note:**\n\nThe \\`limit\\` and \\`offset\\` parameters are separately applied to elements and folders. For example, if you query a \\`limit\\` value of \\`10\\` and an \\`offset\\` value \\`0\\`, the endpoint returns 10 elements and 10 folders for a total of 20 items. The \\`totalCount\\` property in the \\`meta\\` response is the total count of both elements and folders.\n"; +export const parameters = z.object({ + since: z + .string() + .datetime({ offset: true }) + .describe('Return only results created since the given time, in [ISO 8601](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6) format. This value cannot be later than the `until` value.') + .optional(), + until: z + .string() + .datetime({ offset: true }) + .describe('Return only results created until this given time, in [ISO 8601](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6) format. This value cannot be earlier than the `since` value.') + .optional(), + addedBy: z + .number() + .int() + .describe('Return only elements published by the given user ID.') + .optional(), + name: z + .string() + .describe('Return only elements whose name includes the given value. Matching is not case-sensitive.') + .optional(), + summary: z + .string() + .describe('Return only elements whose summary includes the given value. Matching is not case-sensitive.') + .optional(), + description: z + .string() + .describe('Return only elements whose description includes the given value. Matching is not case-sensitive.') + .optional(), + sort: z + .enum(['createdAt', 'updatedAt']) + .describe('Sort the results by the given value. If you use this query parameter, you must also use the `direction` parameter.') + .optional(), + direction: z + .enum(['asc', 'desc']) + .describe('Sort in ascending (`asc`) or descending (`desc`) order. Matching is not case-sensitive. If you use this query parameter, you must also use the `sort` parameter.') + .optional(), + createdBy: z + .number() + .int() + .describe('Return only results created by the given user ID.') + .optional(), + offset: z + .number() + .int() + .describe('The zero-based offset of the first item to return.') + .default(0), + limit: z + .number() + .int() + .describe('The maximum number of elements to return. If the value exceeds the maximum value of `1000`, then the system uses the `1000` value.') + .default(1000), + parentFolderId: z + .number() + .int() + .describe("Return the folders and elements in a specific folder. If this value is `0`, then the endpoint only returns the root folder's elements.") + .default(0), + type: z + .enum(['api', 'folder', 'collection', 'workspace']) + .describe('Filter by the element type.') + .optional(), +}); +export const annotations = { + title: "Gets information about the folders and their elements added to your team's [Private API Network](https://learning.postman.com/docs/collaborating-in-postman/adding-private-network/).\n\n**Note:**\n\nThe \\`limit\\` and \\`offset\\` parameters are separately applied to elements and folders. For example, if you query a \\`limit\\` value of \\`10\\` and an \\`offset\\` value \\`0\\`, the endpoint returns 10 elements and 10 folders for a total of 20 items. The \\`totalCount\\` property in the \\`meta\\` response is the total count of both elements and folders.\n", + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/network/private`; + const query = new URLSearchParams(); + if (params.since !== undefined) + query.set('since', String(params.since)); + if (params.until !== undefined) + query.set('until', String(params.until)); + if (params.addedBy !== undefined) + query.set('addedBy', String(params.addedBy)); + if (params.name !== undefined) + query.set('name', String(params.name)); + if (params.summary !== undefined) + query.set('summary', String(params.summary)); + if (params.description !== undefined) + query.set('description', String(params.description)); + if (params.sort !== undefined) + query.set('sort', String(params.sort)); + if (params.direction !== undefined) + query.set('direction', String(params.direction)); + if (params.createdBy !== undefined) + query.set('createdBy', String(params.createdBy)); + if (params.offset !== undefined) + query.set('offset', String(params.offset)); + if (params.limit !== undefined) + query.set('limit', String(params.limit)); + if (params.parentFolderId !== undefined) + query.set('parentFolderId', String(params.parentFolderId)); + if (params.type !== undefined) + query.set('type', String(params.type)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_all_pan_add_element_requests.js b/dist/src/tools/get_all_pan_add_element_requests.js new file mode 100644 index 0000000..583155f --- /dev/null +++ b/dist/src/tools/get_all_pan_add_element_requests.js @@ -0,0 +1,99 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-all-pan-add-element-requests'; +export const description = "Gets a list requests to add elements to your team's [Private API Network](https://learning.postman.com/docs/collaborating-in-postman/adding-private-network/)."; +export const parameters = z.object({ + since: z + .string() + .datetime({ offset: true }) + .describe('Return only results created since the given time, in [ISO 8601](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6) format. This value cannot be later than the `until` value. To use time-numoffset format, you must use `%2B` URL-encoding for the `+` character.') + .optional(), + until: z + .string() + .datetime({ offset: true }) + .describe('Return only results created until this given time, in [ISO 8601](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6) format. This value cannot be earlier than the `since` value. To use time-numoffset format, you must use `%2B` URL-encoding for the `+` character.') + .optional(), + requestedBy: z + .number() + .int() + .describe("Return a user's element requests by their user ID.") + .optional(), + type: z + .enum(['api', 'folder', 'collection', 'workspace']) + .describe('Filter by the element type.') + .optional(), + status: z.enum(['pending', 'denied']).describe('Filter by the request status.').optional(), + name: z + .string() + .describe('Return only elements whose name includes the given value. Matching is not case-sensitive.') + .optional(), + sort: z + .enum(['createdAt', 'updatedAt']) + .describe('Sort the results by the given value. If you use this query parameter, you must also use the `direction` parameter.') + .optional(), + direction: z + .enum(['asc', 'desc']) + .describe('Sort in ascending (`asc`) or descending (`desc`) order. Matching is not case-sensitive. If you use this query parameter, you must also use the `sort` parameter.') + .optional(), + offset: z + .number() + .int() + .describe('The zero-based offset of the first item to return.') + .default(0), + limit: z + .number() + .int() + .describe('The maximum number of elements to return. If the value exceeds the maximum value of `1000`, then the system uses the `1000` value.') + .default(1000), +}); +export const annotations = { + title: "Gets a list requests to add elements to your team's [Private API Network](https://learning.postman.com/docs/collaborating-in-postman/adding-private-network/).", + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/network/private/network-entity/request/all`; + const query = new URLSearchParams(); + if (params.since !== undefined) + query.set('since', String(params.since)); + if (params.until !== undefined) + query.set('until', String(params.until)); + if (params.requestedBy !== undefined) + query.set('requestedBy', String(params.requestedBy)); + if (params.type !== undefined) + query.set('type', String(params.type)); + if (params.status !== undefined) + query.set('status', String(params.status)); + if (params.name !== undefined) + query.set('name', String(params.name)); + if (params.sort !== undefined) + query.set('sort', String(params.sort)); + if (params.direction !== undefined) + query.set('direction', String(params.direction)); + if (params.offset !== undefined) + query.set('offset', String(params.offset)); + if (params.limit !== undefined) + query.set('limit', String(params.limit)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_all_specs.js b/dist/src/tools/get_all_specs.js new file mode 100644 index 0000000..04c33fd --- /dev/null +++ b/dist/src/tools/get_all_specs.js @@ -0,0 +1,53 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-all-specs'; +export const description = 'Gets all API specifications in a workspace.'; +export const parameters = z.object({ + workspaceId: z.string().describe("The workspace's ID."), + cursor: z + .string() + .describe('The pointer to the first record of the set of paginated results. To view the next response, use the `nextCursor` value for this parameter.') + .optional(), + limit: z + .number() + .int() + .describe('The maximum number of rows to return in the response.') + .default(10), +}); +export const annotations = { + title: 'Gets all API specifications in a workspace.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/specs`; + const query = new URLSearchParams(); + if (params.workspaceId !== undefined) + query.set('workspaceId', String(params.workspaceId)); + if (params.cursor !== undefined) + query.set('cursor', String(params.cursor)); + if (params.limit !== undefined) + query.set('limit', String(params.limit)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_async_spec_task_status.js b/dist/src/tools/get_async_spec_task_status.js new file mode 100644 index 0000000..abfd7f6 --- /dev/null +++ b/dist/src/tools/get_async_spec_task_status.js @@ -0,0 +1,40 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-async-spec-task-status'; +export const description = 'Gets the status of an asynchronous API specification creation task.'; +export const parameters = z.object({ + elementType: z.enum(['collections', 'specs']).describe('The element to filter results by.'), + elementId: z.union([z.string(), z.string()]).describe("The element's ID."), + taskId: z.string().describe("The task's ID."), +}); +export const annotations = { + title: 'Gets the status of an asynchronous API specification creation task.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/${params.elementType}/${params.elementId}/tasks/${params.taskId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_authenticated_user.js b/dist/src/tools/get_authenticated_user.js new file mode 100644 index 0000000..d3fa5dc --- /dev/null +++ b/dist/src/tools/get_authenticated_user.js @@ -0,0 +1,36 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-authenticated-user'; +export const description = 'Gets information about the authenticated user.\n\n**Note:**\n\n- This API returns a different response for users with the [Guest and Partner roles](https://learning.postman.com/docs/collaborating-in-postman/roles-and-permissions/#team-roles).\n- The \\`flow_count\\` response only returns for users on [Free plans](https://www.postman.com/pricing/).\n'; +export const parameters = z.object({}); +export const annotations = { + title: 'Gets information about the authenticated user.\n\n**Note:**\n\n- This API returns a different response for users with the [Guest and Partner roles](https://learning.postman.com/docs/collaborating-in-postman/roles-and-permissions/#team-roles).\n- The \\`flow_count\\` response only returns for users on [Free plans](https://www.postman.com/pricing/).\n', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/me`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_collection.js b/dist/src/tools/get_collection.js new file mode 100644 index 0000000..031052a --- /dev/null +++ b/dist/src/tools/get_collection.js @@ -0,0 +1,52 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-collection'; +export const description = "Gets information about a collection. For a complete list of this endpoint's possible values, refer to the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html)."; +export const parameters = z.object({ + collectionId: z + .string() + .describe('The collection ID must be in the form - (e.g. 12345-33823532ab9e41c9b6fd12d0fd459b8b).'), + access_key: z + .string() + .describe("A collection's read-only access key. Using this query parameter does not require an API key to call the endpoint.") + .optional(), + model: z + .literal('minimal') + .describe("Return a list of only the collection's root-level request (`rootLevelRequests`) and folder (`rootLevelFolders`) IDs instead of the full collection element data.") + .optional(), +}); +export const annotations = { + title: "Gets information about a collection. For a complete list of this endpoint's possible values, refer to the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).", + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}`; + const query = new URLSearchParams(); + if (params.access_key !== undefined) + query.set('access_key', String(params.access_key)); + if (params.model !== undefined) + query.set('model', String(params.model)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_collection_comments.js b/dist/src/tools/get_collection_comments.js new file mode 100644 index 0000000..927b53b --- /dev/null +++ b/dist/src/tools/get_collection_comments.js @@ -0,0 +1,38 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-collection-comments'; +export const description = 'Gets all comments left by users in a collection.'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), +}); +export const annotations = { + title: 'Gets all comments left by users in a collection.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/comments`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_collection_folder.js b/dist/src/tools/get_collection_folder.js new file mode 100644 index 0000000..bf198c5 --- /dev/null +++ b/dist/src/tools/get_collection_folder.js @@ -0,0 +1,54 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-collection-folder'; +export const description = 'Gets information about a folder in a collection.'; +export const parameters = z.object({ + folderId: z.string().describe("The folder's ID."), + collectionId: z.string().describe("The collection's ID."), + ids: z + .boolean() + .describe('If true, returns only properties that contain ID values in the response.') + .optional(), + uid: z.boolean().describe('If true, returns all IDs in UID format (`userId`-`id`).').optional(), + populate: z + .boolean() + .describe("If true, returns all of the collection item's contents.") + .optional(), +}); +export const annotations = { + title: 'Gets information about a folder in a collection.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/folders/${params.folderId}`; + const query = new URLSearchParams(); + if (params.ids !== undefined) + query.set('ids', String(params.ids)); + if (params.uid !== undefined) + query.set('uid', String(params.uid)); + if (params.populate !== undefined) + query.set('populate', String(params.populate)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_collection_forks.js b/dist/src/tools/get_collection_forks.js new file mode 100644 index 0000000..bde9cf8 --- /dev/null +++ b/dist/src/tools/get_collection_forks.js @@ -0,0 +1,57 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-collection-forks'; +export const description = "Gets a collection's forked collections. The response returns data for each fork, such as the fork's ID, the user who forked it, and the fork's creation date."; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's ID."), + cursor: z + .string() + .describe('The pointer to the first record of the set of paginated results. To view the next response, use the `nextCursor` value for this parameter.') + .optional(), + limit: z + .number() + .int() + .describe('The maximum number of rows to return in the response.') + .default(10), + direction: z + .enum(['asc', 'desc']) + .describe('Sort the results by creation date in ascending (`asc`) or descending (`desc`) order.') + .optional(), +}); +export const annotations = { + title: "Gets a collection's forked collections. The response returns data for each fork, such as the fork's ID, the user who forked it, and the fork's creation date.", + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/forks`; + const query = new URLSearchParams(); + if (params.cursor !== undefined) + query.set('cursor', String(params.cursor)); + if (params.limit !== undefined) + query.set('limit', String(params.limit)); + if (params.direction !== undefined) + query.set('direction', String(params.direction)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_collection_request.js b/dist/src/tools/get_collection_request.js new file mode 100644 index 0000000..0ec7a73 --- /dev/null +++ b/dist/src/tools/get_collection_request.js @@ -0,0 +1,54 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-collection-request'; +export const description = 'Gets information about a request in a collection.'; +export const parameters = z.object({ + requestId: z.string().describe("The request's ID."), + collectionId: z.string().describe("The collection's ID."), + ids: z + .boolean() + .describe('If true, returns only properties that contain ID values in the response.') + .optional(), + uid: z.boolean().describe('If true, returns all IDs in UID format (`userId`-`id`).').optional(), + populate: z + .boolean() + .describe("If true, returns all of the collection item's contents.") + .optional(), +}); +export const annotations = { + title: 'Gets information about a request in a collection.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/requests/${params.requestId}`; + const query = new URLSearchParams(); + if (params.ids !== undefined) + query.set('ids', String(params.ids)); + if (params.uid !== undefined) + query.set('uid', String(params.uid)); + if (params.populate !== undefined) + query.set('populate', String(params.populate)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_collection_response.js b/dist/src/tools/get_collection_response.js new file mode 100644 index 0000000..841a9bc --- /dev/null +++ b/dist/src/tools/get_collection_response.js @@ -0,0 +1,54 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-collection-response'; +export const description = 'Gets information about a response in a collection.'; +export const parameters = z.object({ + responseId: z.string().describe("The response's ID."), + collectionId: z.string().describe("The collection's ID."), + ids: z + .boolean() + .describe('If true, returns only properties that contain ID values in the response.') + .optional(), + uid: z.boolean().describe('If true, returns all IDs in UID format (`userId`-`id`).').optional(), + populate: z + .boolean() + .describe("If true, returns all of the collection item's contents.") + .optional(), +}); +export const annotations = { + title: 'Gets information about a response in a collection.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/responses/${params.responseId}`; + const query = new URLSearchParams(); + if (params.ids !== undefined) + query.set('ids', String(params.ids)); + if (params.uid !== undefined) + query.set('uid', String(params.uid)); + if (params.populate !== undefined) + query.set('populate', String(params.populate)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_collection_tags.js b/dist/src/tools/get_collection_tags.js new file mode 100644 index 0000000..a82df12 --- /dev/null +++ b/dist/src/tools/get_collection_tags.js @@ -0,0 +1,38 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-collection-tags'; +export const description = 'Gets all the tags associated with a collection.'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), +}); +export const annotations = { + title: 'Gets all the tags associated with a collection.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/tags`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_collection_updates_tasks.js b/dist/src/tools/get_collection_updates_tasks.js new file mode 100644 index 0000000..307150e --- /dev/null +++ b/dist/src/tools/get_collection_updates_tasks.js @@ -0,0 +1,36 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-collection-updates-tasks'; +export const description = 'Gets the status of an asynchronous collection update task.'; +export const parameters = z.object({ taskId: z.string().describe("The task's ID.") }); +export const annotations = { + title: 'Gets the status of an asynchronous collection update task.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collection-updates-tasks/${params.taskId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_collections.js b/dist/src/tools/get_collections.js new file mode 100644 index 0000000..8f81310 --- /dev/null +++ b/dist/src/tools/get_collections.js @@ -0,0 +1,57 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-collections'; +export const description = 'The workspace ID query is required for this endpoint. If not provided, the LLM should ask the user to provide it.'; +export const parameters = z.object({ + workspace: z.string().describe("The workspace's ID."), + name: z.string().describe('Filter results by collections that match the given name.').optional(), + limit: z + .number() + .int() + .describe('The maximum number of rows to return in the response.') + .optional(), + offset: z + .number() + .int() + .describe('The zero-based offset of the first item to return.') + .optional(), +}); +export const annotations = { + title: 'The workspace ID query is required for this endpoint. If not provided, the LLM should ask the user to provide it.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections`; + const query = new URLSearchParams(); + if (params.workspace !== undefined) + query.set('workspace', String(params.workspace)); + if (params.name !== undefined) + query.set('name', String(params.name)); + if (params.limit !== undefined) + query.set('limit', String(params.limit)); + if (params.offset !== undefined) + query.set('offset', String(params.offset)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_collections_forked_by_user.js b/dist/src/tools/get_collections_forked_by_user.js new file mode 100644 index 0000000..53f883b --- /dev/null +++ b/dist/src/tools/get_collections_forked_by_user.js @@ -0,0 +1,56 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-collections-forked-by-user'; +export const description = "Gets a list of all the authenticated user's forked collections."; +export const parameters = z.object({ + cursor: z + .string() + .describe('The pointer to the first record of the set of paginated results. To view the next response, use the `nextCursor` value for this parameter.') + .optional(), + limit: z + .number() + .int() + .describe('The maximum number of rows to return in the response.') + .default(10), + direction: z + .enum(['asc', 'desc']) + .describe('Sort the results by creation date in ascending (`asc`) or descending (`desc`) order.') + .optional(), +}); +export const annotations = { + title: "Gets a list of all the authenticated user's forked collections.", + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/collection-forks`; + const query = new URLSearchParams(); + if (params.cursor !== undefined) + query.set('cursor', String(params.cursor)); + if (params.limit !== undefined) + query.set('limit', String(params.limit)); + if (params.direction !== undefined) + query.set('direction', String(params.direction)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_duplicate_collection_task_status.js b/dist/src/tools/get_duplicate_collection_task_status.js new file mode 100644 index 0000000..7b72703 --- /dev/null +++ b/dist/src/tools/get_duplicate_collection_task_status.js @@ -0,0 +1,36 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-duplicate-collection-task-status'; +export const description = 'Gets the status of a collection duplication task.'; +export const parameters = z.object({ taskId: z.string().describe("The task's unique ID.") }); +export const annotations = { + title: 'Gets the status of a collection duplication task.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collection-duplicate-tasks/${params.taskId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_environment.js b/dist/src/tools/get_environment.js new file mode 100644 index 0000000..7bad30d --- /dev/null +++ b/dist/src/tools/get_environment.js @@ -0,0 +1,36 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-environment'; +export const description = 'Gets information about an environment.'; +export const parameters = z.object({ environmentId: z.string().describe("The environment's ID.") }); +export const annotations = { + title: 'Gets information about an environment.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/environments/${params.environmentId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_environments.js b/dist/src/tools/get_environments.js new file mode 100644 index 0000000..63bb113 --- /dev/null +++ b/dist/src/tools/get_environments.js @@ -0,0 +1,40 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-environments'; +export const description = 'Gets information about all of your [environments](https://learning.postman.com/docs/sending-requests/managing-environments/).'; +export const parameters = z.object({ + workspace: z.string().describe("The workspace's ID.").optional(), +}); +export const annotations = { + title: 'Gets information about all of your [environments](https://learning.postman.com/docs/sending-requests/managing-environments/).', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/environments`; + const query = new URLSearchParams(); + if (params.workspace !== undefined) + query.set('workspace', String(params.workspace)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_folder_comments.js b/dist/src/tools/get_folder_comments.js new file mode 100644 index 0000000..6e28539 --- /dev/null +++ b/dist/src/tools/get_folder_comments.js @@ -0,0 +1,39 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-folder-comments'; +export const description = 'Gets all comments left by users in a folder.'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + folderId: z.string().describe("The folder's unique ID."), +}); +export const annotations = { + title: 'Gets all comments left by users in a folder.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/folders/${params.folderId}/comments`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_generated_collection_specs.js b/dist/src/tools/get_generated_collection_specs.js new file mode 100644 index 0000000..6b7c1a5 --- /dev/null +++ b/dist/src/tools/get_generated_collection_specs.js @@ -0,0 +1,39 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-generated-collection-specs'; +export const description = 'Gets the API specification generated for the given collection.'; +export const parameters = z.object({ + collectionUid: z.string().describe("The collection's unique ID."), + elementType: z.literal('spec').describe('The `spec` value.'), +}); +export const annotations = { + title: 'Gets the API specification generated for the given collection.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionUid}/generations/${params.elementType}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_mock.js b/dist/src/tools/get_mock.js new file mode 100644 index 0000000..0fc4ebd --- /dev/null +++ b/dist/src/tools/get_mock.js @@ -0,0 +1,36 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-mock'; +export const description = 'Gets information about a mock server.'; +export const parameters = z.object({ mockId: z.string().describe("The mock's ID.") }); +export const annotations = { + title: 'Gets information about a mock server.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/mocks/${params.mockId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_mocks.js b/dist/src/tools/get_mocks.js new file mode 100644 index 0000000..c07c48f --- /dev/null +++ b/dist/src/tools/get_mocks.js @@ -0,0 +1,43 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-mocks'; +export const description = 'Gets all active mock servers. By default, this endpoint returns only mock servers you created across all workspaces.\n\n**Note:**\n\nIf you pass both the \\`teamId\\` and \\`workspace\\` query parameters, this endpoint only accepts the \\`workspace\\` query.\n'; +export const parameters = z.object({ + teamId: z.string().describe('Return only results that belong to the given team ID.').optional(), + workspace: z.string().describe('Return only results found in the given workspace ID.').optional(), +}); +export const annotations = { + title: 'Gets all active mock servers. By default, this endpoint returns only mock servers you created across all workspaces.\n\n**Note:**\n\nIf you pass both the \\`teamId\\` and \\`workspace\\` query parameters, this endpoint only accepts the \\`workspace\\` query.\n', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/mocks`; + const query = new URLSearchParams(); + if (params.teamId !== undefined) + query.set('teamId', String(params.teamId)); + if (params.workspace !== undefined) + query.set('workspace', String(params.workspace)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_monitor.js b/dist/src/tools/get_monitor.js new file mode 100644 index 0000000..9693dc5 --- /dev/null +++ b/dist/src/tools/get_monitor.js @@ -0,0 +1,36 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-monitor'; +export const description = 'Gets information about a monitor.'; +export const parameters = z.object({ monitorId: z.string().describe("The monitor's ID.") }); +export const annotations = { + title: 'Gets information about a monitor.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/monitors/${params.monitorId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_monitors.js b/dist/src/tools/get_monitors.js new file mode 100644 index 0000000..939f16a --- /dev/null +++ b/dist/src/tools/get_monitors.js @@ -0,0 +1,72 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-monitors'; +export const description = 'Gets all monitors.'; +export const parameters = z.object({ + workspace: z.string().describe('Return only results found in the given workspace ID.').optional(), + active: z.boolean().describe('If true, return only active monitors.').default(false), + owner: z + .number() + .int() + .describe('Return only results that belong to the given user ID.') + .optional(), + collectionUid: z.string().describe("Filter the results by a collection's unique ID.").optional(), + environmentUid: z + .string() + .describe("Filter the results by an environment's unique ID.") + .optional(), + cursor: z + .string() + .describe('The pointer to the first record of the set of paginated results. To view the next response, use the `nextCursor` value for this parameter.') + .optional(), + limit: z + .number() + .int() + .describe('The maximum number of rows to return in the response, up to a maximum value of 25. Any value greater than 25 returns a 400 Bad Request response.') + .default(25), +}); +export const annotations = { + title: 'Gets all monitors.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/monitors`; + const query = new URLSearchParams(); + if (params.workspace !== undefined) + query.set('workspace', String(params.workspace)); + if (params.active !== undefined) + query.set('active', String(params.active)); + if (params.owner !== undefined) + query.set('owner', String(params.owner)); + if (params.collectionUid !== undefined) + query.set('collectionUid', String(params.collectionUid)); + if (params.environmentUid !== undefined) + query.set('environmentUid', String(params.environmentUid)); + if (params.cursor !== undefined) + query.set('cursor', String(params.cursor)); + if (params.limit !== undefined) + query.set('limit', String(params.limit)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_request_comments.js b/dist/src/tools/get_request_comments.js new file mode 100644 index 0000000..f3154b1 --- /dev/null +++ b/dist/src/tools/get_request_comments.js @@ -0,0 +1,41 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-request-comments'; +export const description = 'Gets all comments left by users in a request.'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + requestId: z + .string() + .describe("The request ID must contain the team ID as a prefix, in `teamId-requestId` format.\n\nFor example, if you're creating a comment on collection ID `24585957-7b2c98f7-30db-4b67-8685-0079f48a0947` (note on the prefix), and\nthe collection request's ID is `2c450b59-9bbf-729b-6ac0-f92535a7c336`, then the `{requestId}` must be `24585957-2c450b59-9bbf-729b-6ac0-f92535a7c336`.\n"), +}); +export const annotations = { + title: 'Gets all comments left by users in a request.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/requests/${params.requestId}/comments`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_response_comments.js b/dist/src/tools/get_response_comments.js new file mode 100644 index 0000000..fab44d4 --- /dev/null +++ b/dist/src/tools/get_response_comments.js @@ -0,0 +1,39 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-response-comments'; +export const description = 'Gets all comments left by users in a response.'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + responseId: z.string().describe("The response's unique ID."), +}); +export const annotations = { + title: 'Gets all comments left by users in a response.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/responses/${params.responseId}/comments`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_source_collection_status.js b/dist/src/tools/get_source_collection_status.js new file mode 100644 index 0000000..9275163 --- /dev/null +++ b/dist/src/tools/get_source_collection_status.js @@ -0,0 +1,36 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-source-collection-status'; +export const description = 'Checks whether there is a change between the forked collection and its parent (source) collection.\n\nIf the value of the \\`isSourceAhead\\` property is \\`true\\` in the response, then there is a difference between the forked collection and its source collection.\n\n**Note:**\n\nThis endpoint may take a few minutes to return an updated \\`isSourceAhead\\` status.\n'; +export const parameters = z.object({ collectionId: z.string().describe("The collection's ID.") }); +export const annotations = { + title: 'Checks whether there is a change between the forked collection and its parent (source) collection.\n\nIf the value of the \\`isSourceAhead\\` property is \\`true\\` in the response, then there is a difference between the forked collection and its source collection.\n\n**Note:**\n\nThis endpoint may take a few minutes to return an updated \\`isSourceAhead\\` status.\n', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/source-status`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_spec.js b/dist/src/tools/get_spec.js new file mode 100644 index 0000000..1ea73fa --- /dev/null +++ b/dist/src/tools/get_spec.js @@ -0,0 +1,36 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-spec'; +export const description = 'Gets information about an API specification.'; +export const parameters = z.object({ specId: z.string().describe("The spec's ID.") }); +export const annotations = { + title: 'Gets information about an API specification.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/specs/${params.specId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_spec_collections.js b/dist/src/tools/get_spec_collections.js new file mode 100644 index 0000000..0964fd2 --- /dev/null +++ b/dist/src/tools/get_spec_collections.js @@ -0,0 +1,52 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-spec-collections'; +export const description = "Gets all of an API specification's generated collections."; +export const parameters = z.object({ + specId: z.string().describe("The spec's ID."), + elementType: z.literal('collection').describe('The `collection` element type.'), + limit: z + .number() + .int() + .describe('The maximum number of rows to return in the response.') + .default(10), + cursor: z + .string() + .describe('The pointer to the first record of the set of paginated results. To view the next response, use the `nextCursor` value for this parameter.') + .optional(), +}); +export const annotations = { + title: "Gets all of an API specification's generated collections.", + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/specs/${params.specId}/generations/${params.elementType}`; + const query = new URLSearchParams(); + if (params.limit !== undefined) + query.set('limit', String(params.limit)); + if (params.cursor !== undefined) + query.set('cursor', String(params.cursor)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_spec_definition.js b/dist/src/tools/get_spec_definition.js new file mode 100644 index 0000000..c8ab420 --- /dev/null +++ b/dist/src/tools/get_spec_definition.js @@ -0,0 +1,36 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-spec-definition'; +export const description = "Gets the complete contents of an API specification's definition."; +export const parameters = z.object({ specId: z.string().describe("The spec's ID.") }); +export const annotations = { + title: "Gets the complete contents of an API specification's definition.", + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/specs/${params.specId}/definitions`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_status_of_an_async_task.js b/dist/src/tools/get_status_of_an_async_task.js new file mode 100644 index 0000000..916100c --- /dev/null +++ b/dist/src/tools/get_status_of_an_async_task.js @@ -0,0 +1,42 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-status-of-an-async-task'; +export const description = 'Gets the status of an asynchronous task.'; +export const parameters = z.object({ + apiId: z.string().describe("The API's ID."), + taskId: z.string().describe("The task's ID."), + Accept: z + .literal('application/vnd.api.v10+json') + .describe('The `application/vnd.api.v10+json` request header required to use the endpoint.'), +}); +export const annotations = { + title: 'Gets the status of an asynchronous task.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/apis/${params.apiId}/tasks/${params.taskId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_tagged_entities.js b/dist/src/tools/get_tagged_entities.js new file mode 100644 index 0000000..a4123f5 --- /dev/null +++ b/dist/src/tools/get_tagged_entities.js @@ -0,0 +1,69 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-tagged-entities'; +export const description = 'Gets Postman elements (entities) by a given tag. Tags enable you to organize and search [workspaces](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/managing-workspaces/#tagging-a-workspace), [APIs](https://learning.postman.com/docs/designing-and-developing-your-api/managing-apis/#tagging-apis), and [collections](https://learning.postman.com/docs/collections/using-collections/#tagging-a-collection) that contain shared tags.\n\n**Note:**\n\nTagging is available on Postman [**Enterprise** plans](https://www.postman.com/pricing/).\n'; +export const parameters = z.object({ + slug: z + .string() + .regex(new RegExp('^[a-z][a-z0-9-]*[a-z0-9]+$')) + .min(2) + .max(64) + .describe("The tag's ID within a team or individual (non-team) user scope."), + limit: z + .number() + .int() + .lte(50) + .describe('The maximum number of tagged elements to return in a single call.') + .default(10), + direction: z + .enum(['asc', 'desc']) + .describe("The ascending (`asc`) or descending (`desc`) order to sort the results by, based on the time of the entity's tagging.") + .default('desc'), + cursor: z + .string() + .describe('The cursor to get the next set of results in the paginated response. If you pass an invalid value, the API only returns the first set of results.') + .optional(), + entityType: z + .enum(['api', 'collection', 'workspace']) + .describe('Filter results for the given entity type.') + .optional(), +}); +export const annotations = { + title: 'Gets Postman elements (entities) by a given tag. Tags enable you to organize and search [workspaces](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/managing-workspaces/#tagging-a-workspace), [APIs](https://learning.postman.com/docs/designing-and-developing-your-api/managing-apis/#tagging-apis), and [collections](https://learning.postman.com/docs/collections/using-collections/#tagging-a-collection) that contain shared tags.\n\n**Note:**\n\nTagging is available on Postman [**Enterprise** plans](https://www.postman.com/pricing/).\n', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/tags/${params.slug}/entities`; + const query = new URLSearchParams(); + if (params.limit !== undefined) + query.set('limit', String(params.limit)); + if (params.direction !== undefined) + query.set('direction', String(params.direction)); + if (params.cursor !== undefined) + query.set('cursor', String(params.cursor)); + if (params.entityType !== undefined) + query.set('entityType', String(params.entityType)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_workspace.js b/dist/src/tools/get_workspace.js new file mode 100644 index 0000000..aad2008 --- /dev/null +++ b/dist/src/tools/get_workspace.js @@ -0,0 +1,44 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-workspace'; +export const description = "Gets information about a workspace.\n\n**Note:**\n\nThis endpoint's response contains the \\`visibility\\` field. [Visibility](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/managing-workspaces/#changing-workspace-visibility) determines who can access the workspace:\n- \\`personal\\` โ€” Only you can access the workspace.\n- \\`team\\` โ€” All team members can access the workspace.\n- \\`private\\` โ€” Only invited team members can access the workspace ([**Professional** and **Enterprise** plans only](https://www.postman.com/pricing)).\n- \\`public\\` โ€” Everyone can access the workspace.\n- \\`partner\\` โ€” Only invited team members and [partners](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/partner-workspaces/) can access the workspace ([**Professional** and **Enterprise** plans only](https://www.postman.com/pricing)).\n\n### Important\n\nWe have deprecated the \\`name\\` and \\`uid\\` responses in the following array of objects:\n- \\`collections\\`\n- \\`environments\\`\n- \\`mocks\\`\n- \\`monitors\\`\n- \\`apis\\`\n"; +export const parameters = z.object({ + workspaceId: z.string().describe("The workspace's ID."), + include: z + .enum(['mocks:deactivated', 'scim']) + .describe("Include the following information in the endpoint's response:\n- `mocks:deactivated` โ€” Include all deactivated mock servers in the response.\n- `scim` โ€” Return the SCIM user IDs of the workspace creator and who last modified it.\n") + .optional(), +}); +export const annotations = { + title: "Gets information about a workspace.\n\n**Note:**\n\nThis endpoint's response contains the \\`visibility\\` field. [Visibility](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/managing-workspaces/#changing-workspace-visibility) determines who can access the workspace:\n- \\`personal\\` โ€” Only you can access the workspace.\n- \\`team\\` โ€” All team members can access the workspace.\n- \\`private\\` โ€” Only invited team members can access the workspace ([**Professional** and **Enterprise** plans only](https://www.postman.com/pricing)).\n- \\`public\\` โ€” Everyone can access the workspace.\n- \\`partner\\` โ€” Only invited team members and [partners](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/partner-workspaces/) can access the workspace ([**Professional** and **Enterprise** plans only](https://www.postman.com/pricing)).\n\n### Important\n\nWe have deprecated the \\`name\\` and \\`uid\\` responses in the following array of objects:\n- \\`collections\\`\n- \\`environments\\`\n- \\`mocks\\`\n- \\`monitors\\`\n- \\`apis\\`\n", + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/workspaces/${params.workspaceId}`; + const query = new URLSearchParams(); + if (params.include !== undefined) + query.set('include', String(params.include)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_workspace_global_variables.js b/dist/src/tools/get_workspace_global_variables.js new file mode 100644 index 0000000..5ae20cd --- /dev/null +++ b/dist/src/tools/get_workspace_global_variables.js @@ -0,0 +1,36 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-workspace-global-variables'; +export const description = "Gets a workspace's global [variables](https://learning.postman.com/docs/sending-requests/variables/#variable-scopes). Global variables enable you to access data between collections, requests, scripts, and environments and are available throughout a workspace."; +export const parameters = z.object({ workspaceId: z.string().describe("The workspace's ID.") }); +export const annotations = { + title: "Gets a workspace's global [variables](https://learning.postman.com/docs/sending-requests/variables/#variable-scopes). Global variables enable you to access data between collections, requests, scripts, and environments and are available throughout a workspace.", + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/workspaces/${params.workspaceId}/global-variables`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_workspace_tags.js b/dist/src/tools/get_workspace_tags.js new file mode 100644 index 0000000..eff95fc --- /dev/null +++ b/dist/src/tools/get_workspace_tags.js @@ -0,0 +1,36 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-workspace-tags'; +export const description = 'Gets all the tags associated with a workspace.'; +export const parameters = z.object({ workspaceId: z.string().describe("The workspace's ID.") }); +export const annotations = { + title: 'Gets all the tags associated with a workspace.', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/workspaces/${params.workspaceId}/tags`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/get_workspaces.js b/dist/src/tools/get_workspaces.js new file mode 100644 index 0000000..9c51497 --- /dev/null +++ b/dist/src/tools/get_workspaces.js @@ -0,0 +1,56 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'get-workspaces'; +export const description = "Gets all [workspaces](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/creating-workspaces/). The response includes your workspaces and any workspaces that you have access to.\n\n**Note:**\n\nThis endpoint's response contains the visibility field. Visibility determines who can access the workspace:\n- \\`personal\\` โ€” Only you can access the workspace.\n- \\`team\\` โ€” All team members can access the workspace.\n- \\`private\\` โ€” Only invited team members can access the workspace ([**Professional** and **Enterprise** plans only](https://www.postman.com/pricing)).\n- \\`public\\` โ€” Everyone can access the workspace.\n- \\`partner\\` โ€” Only invited team members and [partners](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/partner-workspaces/) can access the workspace ([**Professional** and **Enterprise** plans only](https://www.postman.com/pricing)).\n"; +export const parameters = z.object({ + type: z + .enum(['personal', 'team', 'private', 'public', 'partner']) + .describe('The type of workspace to filter the response by.') + .optional(), + createdBy: z + .number() + .int() + .describe('Return only workspaces created by a specific user ID. For multiple users, pass this value as a comma-separated list of user IDs. The response only returns workspaces that you have access to.') + .optional(), + include: z + .enum(['mocks:deactivated', 'scim']) + .describe("Include the following information in the endpoint's response:\n- `mocks:deactivated` โ€” Include all deactivated mock servers in the response.\n- `scim` โ€” Return the SCIM user IDs of the workspace creator and who last modified it.\n") + .optional(), +}); +export const annotations = { + title: "Gets all [workspaces](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/creating-workspaces/). The response includes your workspaces and any workspaces that you have access to.\n\n**Note:**\n\nThis endpoint's response contains the visibility field. Visibility determines who can access the workspace:\n- \\`personal\\` โ€” Only you can access the workspace.\n- \\`team\\` โ€” All team members can access the workspace.\n- \\`private\\` โ€” Only invited team members can access the workspace ([**Professional** and **Enterprise** plans only](https://www.postman.com/pricing)).\n- \\`public\\` โ€” Everyone can access the workspace.\n- \\`partner\\` โ€” Only invited team members and [partners](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/partner-workspaces/) can access the workspace ([**Professional** and **Enterprise** plans only](https://www.postman.com/pricing)).\n", + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/workspaces`; + const query = new URLSearchParams(); + if (params.type !== undefined) + query.set('type', String(params.type)); + if (params.createdBy !== undefined) + query.set('createdBy', String(params.createdBy)); + if (params.include !== undefined) + query.set('include', String(params.include)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'GET', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/patch_collection.js b/dist/src/tools/patch_collection.js new file mode 100644 index 0000000..9cad90d --- /dev/null +++ b/dist/src/tools/patch_collection.js @@ -0,0 +1,318 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'patch-collection'; +export const description = 'Updates specific collection information, such as its name, events, or its variables. For more information about the \\`auth\\`, \\`variable\\`, and \\`events\\` properties, refer to the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html):\n- For \\`variable\\`, refer to the **Variable List** entry. Also accepts \\`variables\\`.\n- For \\`auth\\`, refer to the **Auth** entry.\n- For \\`events\\`, refer to the **Event List** entry.\n'; +export const parameters = z.object({ + collectionId: z + .string() + .describe('The collection ID must be in the form - (e.g. 12345-33823532ab9e41c9b6fd12d0fd459b8b).'), + collection: z + .object({ + info: z + .object({ + name: z.string().describe("The collection's updated name.").optional(), + description: z.string().describe("The collection's updated description.").optional(), + }) + .describe("An object that contains the collection's updated name and description.") + .optional(), + variable: z + .array(z + .object({ + id: z + .string() + .describe("The variable's ID. Doesn't apply to collection-level variables.") + .optional(), + key: z.string().describe("The variable's key (name).").optional(), + description: z + .string() + .describe("The variable's description. Doesn't apply to collection-level variables.") + .optional(), + value: z.string().describe("The key's value.").optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + disabled: z + .boolean() + .describe('If true, the variable is not enabled. Applies only to query parameter variables.') + .default(false), + }) + .describe('Information about the variable.')) + .describe("A list of the collection's [variables](https://learning.postman.com/docs/sending-requests/variables/variables/). Make certain not to include sensitive information in variables.") + .optional(), + auth: z + .object({ + type: z + .enum([ + 'basic', + 'bearer', + 'apikey', + 'digest', + 'oauth1', + 'oauth2', + 'hawk', + 'awsv4', + 'ntlm', + 'edgegrid', + 'jwt', + 'asap', + ]) + .describe('The authorization type.'), + apikey: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe("The API key's authentication information.") + .optional(), + awsv4: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [AWS Signature](https://learning.postman.com/docs/sending-requests/authorization/aws-signature/) authentication.') + .optional(), + basic: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [Basic Auth](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#basic-auth).') + .optional(), + bearer: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [Bearer Token](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#bearer-token) authentication.') + .optional(), + digest: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [Digest](https://learning.postman.com/docs/sending-requests/authorization/digest-auth/) access authentication.') + .optional(), + edgegrid: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [Akamai Edgegrid](https://learning.postman.com/docs/sending-requests/authorization/akamai-edgegrid/) authentication.') + .optional(), + hawk: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [Hawk](https://learning.postman.com/docs/sending-requests/authorization/hawk-authentication/) authentication.') + .optional(), + ntlm: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [NTLM](https://learning.postman.com/docs/sending-requests/authorization/ntlm-authentication/) authentication.') + .optional(), + oauth1: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [OAuth1](https://learning.postman.com/docs/sending-requests/authorization/oauth-10/) authentication.') + .optional(), + oauth2: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [OAuth2](https://learning.postman.com/docs/sending-requests/authorization/oauth-20/) authentication.') + .optional(), + jwt: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for JWT (JSON Web Token). Includes the `payload`, `secret`, `algorithm`, `addTokenTo`, and `headerPrefix` properties.') + .optional(), + asap: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for ASAP (Atlassian S2S Authentication Protocol). Includes the `kid`, `aud`, `iss`, `alg`, `privateKey`, and `claims` properties.') + .optional(), + }) + .describe('The [authorization type supported by Postman](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).') + .optional(), + events: z + .array(z + .object({ + id: z.string().describe("The event's ID.").optional(), + listen: z + .enum(['test', 'prerequest']) + .describe('The `prerequest` (pre-request) or `test` (post-response) value.'), + script: z + .object({ + id: z.string().describe("The script's ID.").optional(), + type: z + .string() + .describe('The type of script. For example, `text/javascript`.') + .optional(), + exec: z + .array(z.string().nullable()) + .describe('A list of script strings, where each line represents a line of code. Separate lines makes it easy to track script changes.') + .optional(), + }) + .describe('Information about the Javascript code that can be used to to perform setup or teardown operations in a response.') + .optional(), + }) + .describe("Information about the collection's events.")) + .optional(), + }) + .optional(), +}); +export const annotations = { + title: 'Updates specific collection information, such as its name, events, or its variables. For more information about the \\`auth\\`, \\`variable\\`, and \\`events\\` properties, refer to the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html):\n- For \\`variable\\`, refer to the **Variable List** entry. Also accepts \\`variables\\`.\n- For \\`auth\\`, refer to the **Auth** entry.\n- For \\`events\\`, refer to the **Event List** entry.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.collection !== undefined) + bodyPayload.collection = params.collection; + const result = await fetchPostmanAPI(url, { + method: 'PATCH', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/patch_environment.js b/dist/src/tools/patch_environment.js new file mode 100644 index 0000000..0f952c9 --- /dev/null +++ b/dist/src/tools/patch_environment.js @@ -0,0 +1,36 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'patch-environment'; +export const description = 'Updates specific environment properties, such as its name and variables.\n\n**Note:**\n\n- The request body size cannot exceed the maximum allowed size of 30MB.\n- If you receive an HTTP \\`411 Length Required\\` error response, manually pass the \\`Content-Length\\` header and its value in the request header.\n'; +export const parameters = z.object({ environmentId: z.string().describe("The environment's ID.") }); +export const annotations = { + title: 'Updates specific environment properties, such as its name and variables.\n\n**Note:**\n\n- The request body size cannot exceed the maximum allowed size of 30MB.\n- If you receive an HTTP \\`411 Length Required\\` error response, manually pass the \\`Content-Length\\` header and its value in the request header.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/environments/${params.environmentId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'PATCH', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/post_pan_element_or_folder.js b/dist/src/tools/post_pan_element_or_folder.js new file mode 100644 index 0000000..4da5a9f --- /dev/null +++ b/dist/src/tools/post_pan_element_or_folder.js @@ -0,0 +1,36 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'post-pan-element-or-folder'; +export const description = "Publishes a element or creates a folder in your team's [Private API Network](https://learning.postman.com/docs/collaborating-in-postman/adding-private-network/). An element is a Postman API, collection, or workspace.\n\n**Note:**\n\nYou can only pass one element object type per call. For example, you cannot pass both \\`api\\` and \\`collection\\` in a single request.\n"; +export const parameters = z.object({}); +export const annotations = { + title: "Publishes a element or creates a folder in your team's [Private API Network](https://learning.postman.com/docs/collaborating-in-postman/adding-private-network/). An element is a Postman API, collection, or workspace.\n\n**Note:**\n\nYou can only pass one element object type per call. For example, you cannot pass both \\`api\\` and \\`collection\\` in a single request.\n", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; +export async function handler(params, extra) { + try { + const endpoint = `/network/private`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'POST', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/publish_documentation.js b/dist/src/tools/publish_documentation.js new file mode 100644 index 0000000..a374e8e --- /dev/null +++ b/dist/src/tools/publish_documentation.js @@ -0,0 +1,123 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'publish-documentation'; +export const description = "Publishes a collection's documentation. This makes it publicly available to anyone with the link to the documentation.\n\n**Note:**\n\n- Your [Postman plan](https://www.postman.com/pricing/) impacts your use of these endpoints:\n - For **Free** and **Basic** users, you must have permissions to edit the collection.\n - If [API Governance and Security](https://learning.postman.com/docs/api-governance/configurable-rules/configurable-rules-overview/) is enabled for your [**Enterprise**](https://www.postman.com/pricing/) team, only users with the [Community Manager role](https://learning.postman.com/docs/collaborating-in-postman/roles-and-permissions/#team-roles) can publish documentation.\n- Publishing is only supported for collections with HTTP requests.\n- You cannot publish a collection added to an API.\n"; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + environmentUid: z + .string() + .describe("The unique ID of the environment to publish with the documentation. The initial values of all variables are published with the documentation. Make certain they don't contain sensitive information such as passwords or tokens.") + .optional(), + customColor: z + .object({ + highlight: z + .string() + .describe("The hexcode color code for the documentation's highlighting.") + .optional(), + rightSidebar: z + .string() + .describe("The hexcode color code for the documentation's right sidebar color.") + .optional(), + topBar: z + .string() + .describe("The hexcode color code for the documentation's top bar color.") + .optional(), + }) + .describe("The theme's colors, in six digit hexcode. The values in this object must match the hexcode values of either the `light` or `dark` theme defined in the `appearance` object."), + documentationLayout: z + .enum(['classic-single-column', 'classic-double-column']) + .describe("The documentation's default layout style:\n- `classic-single-column` โ€” Displays sample code inline beneath each request.\n- `classic-double-column` โ€” Displays sample code in a column next to the documentation.\n") + .default('classic-single-column'), + customization: z + .object({ + metaTags: z + .array(z.object({ + name: z + .string() + .describe("The key's name:\n - `title` โ€” The title of your documentation. This value appears in relevant search queries and browser tabs. By default, the system uses the collection's name for the documentation title.\n - `description` โ€” The documentation's description. This provides brief information about your document and lets users know what it contains. By default, the system uses the collection's description content.\n"), + value: z.string().describe("The `name` key's value."), + })) + .describe("The key-pair values that contain the documentation's `title` and `description` metadata information.") + .optional(), + appearance: z + .object({ + default: z + .enum(['light', 'dark']) + .describe('The default color theme (`light` or `dark`). Documentation uses the given theme value by default.') + .optional(), + themes: z + .array(z.object({ + name: z.enum(['dark', 'light']).describe('The `light` or `dark` theme.').optional(), + colors: z + .object({ + highlight: z + .string() + .describe("The hexcode color code for the documentation's highlighting.") + .optional(), + rightSidebar: z + .string() + .describe("The hexcode color code for the documentation's right sidebar color.") + .optional(), + topBar: z + .string() + .describe("The hexcode color code for the documentation's top bar color.") + .optional(), + }) + .describe("The theme's colors, in six digit hexcode. The values in this object must match the hexcode values of either the `light` or `dark` theme defined in the `appearance` object.") + .optional(), + logo: z + .string() + .nullable() + .describe("The URL to the documentation's logo image. By default, public documentation uses your team logo.") + .optional(), + })) + .describe('A list of theme settings for the `light` and `dark` themes.') + .optional(), + }) + .describe('Information about the documentation appearance, such as colors and theme.') + .optional(), + }) + .describe("Information about the documentation's customization."), +}); +export const annotations = { + title: "Publishes a collection's documentation. This makes it publicly available to anyone with the link to the documentation.\n\n**Note:**\n\n- Your [Postman plan](https://www.postman.com/pricing/) impacts your use of these endpoints:\n - For **Free** and **Basic** users, you must have permissions to edit the collection.\n - If [API Governance and Security](https://learning.postman.com/docs/api-governance/configurable-rules/configurable-rules-overview/) is enabled for your [**Enterprise**](https://www.postman.com/pricing/) team, only users with the [Community Manager role](https://learning.postman.com/docs/collaborating-in-postman/roles-and-permissions/#team-roles) can publish documentation.\n- Publishing is only supported for collections with HTTP requests.\n- You cannot publish a collection added to an API.\n", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/public-documentations`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.environmentUid !== undefined) + bodyPayload.environmentUid = params.environmentUid; + if (params.customColor !== undefined) + bodyPayload.customColor = params.customColor; + if (params.documentationLayout !== undefined) + bodyPayload.documentationLayout = params.documentationLayout; + if (params.customization !== undefined) + bodyPayload.customization = params.customization; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/publish_mock.js b/dist/src/tools/publish_mock.js new file mode 100644 index 0000000..4fca16d --- /dev/null +++ b/dist/src/tools/publish_mock.js @@ -0,0 +1,36 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'publish-mock'; +export const description = 'Publishes a mock server. Publishing a mock server sets its **Access Control** configuration setting to public.'; +export const parameters = z.object({ mockId: z.string().describe("The mock's ID.") }); +export const annotations = { + title: 'Publishes a mock server. Publishing a mock server sets its **Access Control** configuration setting to public.', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; +export async function handler(params, extra) { + try { + const endpoint = `/mocks/${params.mockId}/publish`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'POST', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/pull_collection_changes.js b/dist/src/tools/pull_collection_changes.js new file mode 100644 index 0000000..5be5f62 --- /dev/null +++ b/dist/src/tools/pull_collection_changes.js @@ -0,0 +1,36 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'pull-collection-changes'; +export const description = "Pulls the changes from a parent (source) collection into the forked collection. In the endpoint's response:\n\n- The \\`destinationId\\` is the ID of the forked collection.\n- The \\`sourceId\\` is the ID of the source collection.\n"; +export const parameters = z.object({ collectionId: z.string().describe("The collection's ID.") }); +export const annotations = { + title: "Pulls the changes from a parent (source) collection into the forked collection. In the endpoint's response:\n\n- The \\`destinationId\\` is the ID of the forked collection.\n- The \\`sourceId\\` is the ID of the source collection.\n", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/pulls`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/put_collection.js b/dist/src/tools/put_collection.js new file mode 100644 index 0000000..07e16ec --- /dev/null +++ b/dist/src/tools/put_collection.js @@ -0,0 +1,913 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'put-collection'; +export const description = "Replaces the contents of a collection using the [Postman Collection v2.1.0 schema format](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html). Include the collection's ID values in the request body. If you do not, the endpoint removes the existing items and creates new items.\n\nTo perform an update asynchronously, use the \\`Prefer\\` header with the \\`respond-async\\` value. When performing an async update, this endpoint returns a HTTP \\`202 Accepted\\` response.\n\n> The maximum collection size this endpoint accepts cannot exceed 100 MB.\n\nFor a complete list of available property values for this endpoint, use the following references available in the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html):\n- \\`info\\` object โ€” Refer to the **Information** entry.\n- \\`item\\` object โ€” Refer to the **Items** entry.\n- For all other possible values, refer to the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n- For protocol profile behavior, refer to Postman's [Protocol Profile Behavior documentation](https://github.com/postmanlabs/postman-runtime/blob/develop/docs/protocol-profile-behavior.md).\n\n**Note:**\n\n- If you don't include the collection items' ID values from the request body, the endpoint **removes** the existing items and recreates the items with new ID values.\n- To copy another collection's contents to the given collection, remove all ID values before you pass it in this endpoint. If you do not, this endpoint returns an error. These values include the \\`id\\`, \\`uid\\`, and \\`postman_id\\` values.\n"; +export const parameters = z.object({ + collectionId: z + .string() + .describe('The collection ID must be in the form - (e.g. 12345-33823532ab9e41c9b6fd12d0fd459b8b).'), + Prefer: z + .literal('respond-async') + .describe('The `respond-async` header to perform the update asynchronously.') + .optional(), + collection: z + .object({ + info: z + .object({ + name: z.string().describe("The collection's name."), + _postman_id: z + .string() + .describe("The collection's Postman ID. This field exists for Postman Collection Format v1 compatibility.") + .optional(), + description: z.string().describe("The collection's description.").optional(), + schema: z + .literal('https://schema.getpostman.com/json/collection/v2.1.0/collection.json') + .describe('The "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" Postman Collection Format v2.1.0 schema.'), + updatedAt: z + .string() + .datetime({ offset: true }) + .describe('The date and time when the collection was last updated.') + .optional(), + createdat: z + .string() + .datetime({ offset: true }) + .describe('The date and time when the collection was created.') + .optional(), + lastUpdatedBy: z + .string() + .describe('The user ID of the person who last updated the collection.') + .optional(), + uid: z.string().describe("The collection's unique ID.").optional(), + }) + .describe('Information about the collection.'), + item: z.array(z + .object({ + id: z.string().describe("The collection item's ID."), + name: z.string().describe("The item's name.").optional(), + description: z.string().nullable().describe("The item's description.").optional(), + variable: z + .array(z + .object({ + id: z + .string() + .describe("The variable's ID. Doesn't apply to collection-level variables.") + .optional(), + key: z.string().describe("The variable's key (name).").optional(), + description: z + .string() + .describe("The variable's description. Doesn't apply to collection-level variables.") + .optional(), + value: z.string().describe("The key's value.").optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + disabled: z + .boolean() + .describe('If true, the variable is not enabled. Applies only to query parameter variables.') + .default(false), + }) + .describe('Information about the variable.')) + .describe("A list of the collection's [variables](https://learning.postman.com/docs/sending-requests/variables/variables/). Make certain not to include sensitive information in variables.") + .optional(), + event: z + .array(z + .object({ + id: z.string().describe("The event's ID.").optional(), + listen: z + .enum(['test', 'prerequest']) + .describe('The `prerequest` (pre-request) or `test` (post-response) value.'), + script: z + .object({ + id: z.string().describe("The script's ID.").optional(), + type: z + .string() + .describe('The type of script. For example, `text/javascript`.') + .optional(), + exec: z + .array(z.string().nullable()) + .describe('A list of script strings, where each line represents a line of code. Separate lines makes it easy to track script changes.') + .optional(), + }) + .describe('Information about the Javascript code that can be used to to perform setup or teardown operations in a response.') + .optional(), + }) + .describe("Information about the collection's events.")) + .describe('A list of scripts configured to run when specific events occur. These scripts can be referenced in the collection by their ID.') + .optional(), + request: z + .object({ + url: z + .union([ + z.string().nullable().describe("The request's raw URL."), + z.object({ + raw: z.string().describe("The request's raw URL.").optional(), + protocol: z.string().describe('The request protocol.').optional(), + host: z.array(z.string().nullable()).describe("The host's URL.").optional(), + path: z + .array(z.string()) + .describe("A list of the URL's path components.") + .optional(), + port: z + .string() + .describe("The URL's port number. An empty value indicates port `80` (http) or `443` (https).") + .optional(), + query: z + .array(z.object({ + key: z + .string() + .nullable() + .describe("The query parameter's key.") + .optional(), + value: z.string().nullable().describe("The key's value.").optional(), + disabled: z + .boolean() + .describe("If true, the query parameter isn't sent with the request.") + .default(false), + description: z + .string() + .nullable() + .describe("The query parameter's description.") + .optional(), + })) + .describe('A list of query parameters. These are the query string parts of the URL, parsed as separate variables.') + .optional(), + }), + ]) + .describe('Information about the URL.') + .optional(), + auth: z + .object({ + type: z + .enum([ + 'basic', + 'bearer', + 'apikey', + 'digest', + 'oauth1', + 'oauth2', + 'hawk', + 'awsv4', + 'ntlm', + 'edgegrid', + 'jwt', + 'asap', + ]) + .describe('The authorization type.'), + apikey: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe("The API key's authentication information.") + .optional(), + awsv4: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [AWS Signature](https://learning.postman.com/docs/sending-requests/authorization/aws-signature/) authentication.') + .optional(), + basic: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [Basic Auth](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#basic-auth).') + .optional(), + bearer: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [Bearer Token](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#bearer-token) authentication.') + .optional(), + digest: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [Digest](https://learning.postman.com/docs/sending-requests/authorization/digest-auth/) access authentication.') + .optional(), + edgegrid: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [Akamai Edgegrid](https://learning.postman.com/docs/sending-requests/authorization/akamai-edgegrid/) authentication.') + .optional(), + hawk: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [Hawk](https://learning.postman.com/docs/sending-requests/authorization/hawk-authentication/) authentication.') + .optional(), + ntlm: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [NTLM](https://learning.postman.com/docs/sending-requests/authorization/ntlm-authentication/) authentication.') + .optional(), + oauth1: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [OAuth1](https://learning.postman.com/docs/sending-requests/authorization/oauth-10/) authentication.') + .optional(), + oauth2: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [OAuth2](https://learning.postman.com/docs/sending-requests/authorization/oauth-20/) authentication.') + .optional(), + jwt: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for JWT (JSON Web Token). Includes the `payload`, `secret`, `algorithm`, `addTokenTo`, and `headerPrefix` properties.') + .optional(), + asap: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for ASAP (Atlassian S2S Authentication Protocol). Includes the `kid`, `aud`, `iss`, `alg`, `privateKey`, and `claims` properties.') + .optional(), + }) + .describe('The [authorization type supported by Postman](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).') + .optional(), + method: z.string().describe("The request's standard HTTP method.").optional(), + description: z + .string() + .nullable() + .describe("The request's description.") + .optional(), + header: z + .array(z + .object({ + key: z + .string() + .describe("The header's key, such as `Content-Type` or `X-Custom-Header`."), + value: z.string().describe("The header key's value."), + description: z + .string() + .nullable() + .describe("The header's description.") + .optional(), + }) + .describe('Information about the header.')) + .describe('A list of headers.') + .optional(), + body: z + .object({ + mode: z + .enum(['raw', 'urlencoded', 'formdata', 'file', 'graphql']) + .describe('The data associated with the request.') + .optional(), + raw: z + .string() + .describe('If the `mode` value is `raw`, the raw content of the request body.') + .optional(), + urlencoded: z + .array(z.object({ + key: z.string().describe('The key value.'), + value: z.string().describe("The key's value.").optional(), + description: z + .string() + .nullable() + .describe("The key's description.") + .optional(), + })) + .describe('A list of x-www-form-encoded key/value pairs.') + .optional(), + formdata: z + .array(z.record(z.any()).and(z.union([ + z.object({ + key: z.string().describe('The key value.').optional(), + value: z.string().describe("The key's value.").optional(), + type: z.literal('text').describe('The `text` value.').optional(), + contentType: z + .string() + .describe('The form-data Content-Type header.') + .optional(), + description: z + .string() + .nullable() + .describe("The key's description.") + .optional(), + }), + z.object({ + key: z.string().describe('The key value.').optional(), + src: z + .any() + .superRefine((x, ctx) => { + const schemas = [z.string().nullable(), z.array(z.string())]; + const errors = schemas.reduce((errors, schema) => ((result) => result.error ? [...errors, result.error] : errors)(schema.safeParse(x)), []); + if (schemas.length - errors.length !== 1) { + ctx.addIssue({ + path: ctx.path, + code: 'invalid_union', + unionErrors: errors, + message: 'Invalid input: Should pass single schema', + }); + } + }) + .optional(), + type: z.literal('file').describe('The `file` value.').optional(), + contentType: z + .string() + .describe('The form-data Content-Type header.') + .optional(), + description: z + .string() + .nullable() + .describe("The key's description.") + .optional(), + }), + ]))) + .describe('If the `mode` value is `formdata`, then a list of form-data key/pair values.') + .optional(), + file: z + .object({ + src: z + .string() + .nullable() + .describe('The name of the file to upload (not its path). A null value indicates that no file is selected as a part of the request body.') + .optional(), + }) + .describe('If the `mode` value is `file`, an object containing the file request information.') + .optional(), + graphql: z + .object({ + query: z.string().describe('The GraphQL query.').optional(), + variables: z + .string() + .nullable() + .describe('The GraphQL query variables, in JSON format.') + .optional(), + }) + .describe('If the `mode` value is `graphql`, an object containing the GraphQL request information.') + .optional(), + options: z + .record(z.any()) + .describe('Additional configurations and options set for various modes.') + .optional(), + }) + .describe("Information about the collection's request body.") + .optional(), + }) + .describe('Information about the collection request.') + .optional(), + protocolProfileBehavior: z + .object({ + strictSSL: z + .boolean() + .describe('If true, enables certificate verification.') + .optional(), + followRedirects: z + .boolean() + .describe('If true, follow HTTP 3xx responses as redirects.') + .optional(), + maxRedirects: z + .number() + .describe('The maximum number of redirects to follow.') + .optional(), + disableBodyPruning: z + .boolean() + .describe('If true, disables request body pruning for the GET, COPY, HEAD, PURGE, and UNLOCK methods.') + .optional(), + disableUrlEncoding: z + .boolean() + .describe('If true, disables the percent encoding of auth, path, query, and fragment URL segments.') + .optional(), + disabledSystemHeaders: z + .object({ + 'cache-control': z.boolean().optional(), + 'postman-token': z.boolean().optional(), + 'content-type': z.boolean().optional(), + 'content-length': z.boolean().optional(), + 'accept-encoding': z.boolean().optional(), + connection: z.boolean().optional(), + host: z.boolean().optional(), + }) + .describe('Disable the system headers which are added implicitly.') + .optional(), + insecureHTTPParser: z + .boolean() + .describe('If true, uses an insecure HTTP parser that accepts invalid HTTP headers.') + .optional(), + followOriginalHttpMethod: z + .boolean() + .describe('If true, redirects with the original HTTP method. Redirects with the GET HTTP method by default.') + .optional(), + followAuthorizationHeader: z + .boolean() + .describe('If true, retains the `authorization` header when a redirect happens to a different hostname.') + .optional(), + protocolVersion: z + .enum(['http1', 'http2', 'auto']) + .describe('The HTTP protocol version to use. Supports the `http1`, `http2`, and `auto` values.') + .optional(), + removeRefererHeaderOnRedirect: z + .boolean() + .describe('If true, removes the `referer` header when a redirect happens.') + .optional(), + tlsPreferServerCiphers: z + .boolean() + .describe("If true, uses the server's cipher suite order instead of the client's during negotiation.") + .optional(), + tlsDisabledProtocols: z + .array(z.string()) + .describe('The SSL and TLS protocol versions to disable during negotiation.') + .optional(), + tlsCipherSelection: z + .array(z.string()) + .describe('The order of cipher suites that the SSL server profile uses to establish a secure connection.') + .optional(), + }) + .describe('The [settings](https://learning.postman.com/docs/sending-requests/create-requests/request-settings/) used to alter the [Protocol Profile Behavior](https://github.com/postmanlabs/postman-runtime/blob/develop/docs/protocol-profile-behavior.md) of sending a request.') + .optional(), + uid: z.string().describe("The collection item's unique ID.").optional(), + }) + .describe('Information about the collection request or folder.')), + event: z + .array(z + .object({ + id: z.string().describe("The event's ID.").optional(), + listen: z + .enum(['test', 'prerequest']) + .describe('The `prerequest` (pre-request) or `test` (post-response) value.'), + script: z + .object({ + id: z.string().describe("The script's ID.").optional(), + type: z + .string() + .describe('The type of script. For example, `text/javascript`.') + .optional(), + exec: z + .array(z.string().nullable()) + .describe('A list of script strings, where each line represents a line of code. Separate lines makes it easy to track script changes.') + .optional(), + }) + .describe('Information about the Javascript code that can be used to to perform setup or teardown operations in a response.') + .optional(), + }) + .describe("Information about the collection's events.")) + .describe('A list of scripts configured to run when specific events occur. These scripts can be referenced in the collection by their ID.') + .optional(), + variable: z + .array(z + .object({ + id: z + .string() + .describe("The variable's ID. Doesn't apply to collection-level variables.") + .optional(), + key: z.string().describe("The variable's key (name).").optional(), + description: z + .string() + .describe("The variable's description. Doesn't apply to collection-level variables.") + .optional(), + value: z.string().describe("The key's value.").optional(), + type: z + .enum(['string', 'boolean', 'integer']) + .describe("The variable's type.") + .optional(), + disabled: z + .boolean() + .describe('If true, the variable is not enabled. Applies only to query parameter variables.') + .default(false), + }) + .describe('Information about the variable.')) + .describe("A list of the collection's [variables](https://learning.postman.com/docs/sending-requests/variables/variables/). Make certain not to include sensitive information in variables.") + .optional(), + auth: z + .object({ + type: z + .enum([ + 'basic', + 'bearer', + 'apikey', + 'digest', + 'oauth1', + 'oauth2', + 'hawk', + 'awsv4', + 'ntlm', + 'edgegrid', + 'jwt', + 'asap', + ]) + .describe('The authorization type.'), + apikey: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe("The API key's authentication information.") + .optional(), + awsv4: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [AWS Signature](https://learning.postman.com/docs/sending-requests/authorization/aws-signature/) authentication.') + .optional(), + basic: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [Basic Auth](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#basic-auth).') + .optional(), + bearer: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [Bearer Token](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/#bearer-token) authentication.') + .optional(), + digest: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [Digest](https://learning.postman.com/docs/sending-requests/authorization/digest-auth/) access authentication.') + .optional(), + edgegrid: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [Akamai Edgegrid](https://learning.postman.com/docs/sending-requests/authorization/akamai-edgegrid/) authentication.') + .optional(), + hawk: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [Hawk](https://learning.postman.com/docs/sending-requests/authorization/hawk-authentication/) authentication.') + .optional(), + ntlm: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [NTLM](https://learning.postman.com/docs/sending-requests/authorization/ntlm-authentication/) authentication.') + .optional(), + oauth1: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [OAuth1](https://learning.postman.com/docs/sending-requests/authorization/oauth-10/) authentication.') + .optional(), + oauth2: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for [OAuth2](https://learning.postman.com/docs/sending-requests/authorization/oauth-20/) authentication.') + .optional(), + jwt: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for JWT (JSON Web Token). Includes the `payload`, `secret`, `algorithm`, `addTokenTo`, and `headerPrefix` properties.') + .optional(), + asap: z + .array(z + .object({ + key: z.string().describe("The auth method's key value."), + value: z + .union([z.string(), z.array(z.record(z.any()))]) + .describe("The key's value.") + .optional(), + type: z + .enum(['string', 'boolean', 'number', 'array', 'object', 'any']) + .describe("The value's type.") + .optional(), + }) + .describe('Information about the supported Postman [authorization type](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).')) + .describe('The attributes for ASAP (Atlassian S2S Authentication Protocol). Includes the `kid`, `aud`, `iss`, `alg`, `privateKey`, and `claims` properties.') + .optional(), + }) + .describe('The [authorization type supported by Postman](https://learning.postman.com/docs/sending-requests/authorization/authorization-types/).') + .optional(), + protocolProfileBehavior: z + .object({ + strictSSL: z.boolean().describe('If true, enables certificate verification.').optional(), + followRedirects: z + .boolean() + .describe('If true, follow HTTP 3xx responses as redirects.') + .optional(), + maxRedirects: z + .number() + .describe('The maximum number of redirects to follow.') + .optional(), + disableBodyPruning: z + .boolean() + .describe('If true, disables request body pruning for the GET, COPY, HEAD, PURGE, and UNLOCK methods.') + .optional(), + disableUrlEncoding: z + .boolean() + .describe('If true, disables the percent encoding of auth, path, query, and fragment URL segments.') + .optional(), + disabledSystemHeaders: z + .object({ + 'cache-control': z.boolean().optional(), + 'postman-token': z.boolean().optional(), + 'content-type': z.boolean().optional(), + 'content-length': z.boolean().optional(), + 'accept-encoding': z.boolean().optional(), + connection: z.boolean().optional(), + host: z.boolean().optional(), + }) + .describe('Disable the system headers which are added implicitly.') + .optional(), + insecureHTTPParser: z + .boolean() + .describe('If true, uses an insecure HTTP parser that accepts invalid HTTP headers.') + .optional(), + followOriginalHttpMethod: z + .boolean() + .describe('If true, redirects with the original HTTP method. Redirects with the GET HTTP method by default.') + .optional(), + followAuthorizationHeader: z + .boolean() + .describe('If true, retains the `authorization` header when a redirect happens to a different hostname.') + .optional(), + protocolVersion: z + .enum(['http1', 'http2', 'auto']) + .describe('The HTTP protocol version to use. Supports the `http1`, `http2`, and `auto` values.') + .optional(), + removeRefererHeaderOnRedirect: z + .boolean() + .describe('If true, removes the `referer` header when a redirect happens.') + .optional(), + tlsPreferServerCiphers: z + .boolean() + .describe("If true, uses the server's cipher suite order instead of the client's during negotiation.") + .optional(), + tlsDisabledProtocols: z + .array(z.string()) + .describe('The SSL and TLS protocol versions to disable during negotiation.') + .optional(), + tlsCipherSelection: z + .array(z.string()) + .describe('The order of cipher suites that the SSL server profile uses to establish a secure connection.') + .optional(), + }) + .describe('The [settings](https://learning.postman.com/docs/sending-requests/create-requests/request-settings/) used to alter the [Protocol Profile Behavior](https://github.com/postmanlabs/postman-runtime/blob/develop/docs/protocol-profile-behavior.md) of sending a request.') + .optional(), + }) + .optional(), +}); +export const annotations = { + title: "Replaces the contents of a collection using the [Postman Collection v2.1.0 schema format](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html). Include the collection's ID values in the request body. If you do not, the endpoint removes the existing items and creates new items.\n\nTo perform an update asynchronously, use the \\`Prefer\\` header with the \\`respond-async\\` value. When performing an async update, this endpoint returns a HTTP \\`202 Accepted\\` response.\n\n> The maximum collection size this endpoint accepts cannot exceed 100 MB.\n\nFor a complete list of available property values for this endpoint, use the following references available in the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html):\n- \\`info\\` object โ€” Refer to the **Information** entry.\n- \\`item\\` object โ€” Refer to the **Items** entry.\n- For all other possible values, refer to the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n- For protocol profile behavior, refer to Postman's [Protocol Profile Behavior documentation](https://github.com/postmanlabs/postman-runtime/blob/develop/docs/protocol-profile-behavior.md).\n\n**Note:**\n\n- If you don't include the collection items' ID values from the request body, the endpoint **removes** the existing items and recreates the items with new ID values.\n- To copy another collection's contents to the given collection, remove all ID values before you pass it in this endpoint. If you do not, this endpoint returns an error. These values include the \\`id\\`, \\`uid\\`, and \\`postman_id\\` values.\n", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.collection !== undefined) + bodyPayload.collection = params.collection; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/put_environment.js b/dist/src/tools/put_environment.js new file mode 100644 index 0000000..c81fd57 --- /dev/null +++ b/dist/src/tools/put_environment.js @@ -0,0 +1,57 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'put-environment'; +export const description = 'Replaces all the contents of an environment with the given information.\n\n**Note:**\n\n- The request body size cannot exceed the maximum allowed size of 30MB.\n- If you receive an HTTP \\`411 Length Required\\` error response, manually pass the \\`Content-Length\\` header and its value in the request header.\n'; +export const parameters = z.object({ + environmentId: z.string().describe("The environment's ID."), + environment: z + .object({ + name: z.string().describe("The environment's name.").optional(), + values: z + .array(z.object({ + enabled: z.boolean().describe('If true, the variable is enabled.').optional(), + key: z.string().describe("The variable's name.").optional(), + value: z.string().describe("The variable's value.").optional(), + type: z.enum(['secret', 'default']).describe('The variable type.').optional(), + })) + .describe("Information about the environment's variables.") + .optional(), + }) + .optional(), +}); +export const annotations = { + title: 'Replaces all the contents of an environment with the given information.\n\n**Note:**\n\n- The request body size cannot exceed the maximum allowed size of 30MB.\n- If you receive an HTTP \\`411 Length Required\\` error response, manually pass the \\`Content-Length\\` header and its value in the request header.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/environments/${params.environmentId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.environment !== undefined) + bodyPayload.environment = params.environment; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/resolve_comment_thread.js b/dist/src/tools/resolve_comment_thread.js new file mode 100644 index 0000000..14cfd92 --- /dev/null +++ b/dist/src/tools/resolve_comment_thread.js @@ -0,0 +1,38 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'resolve-comment-thread'; +export const description = 'Resolves a comment and any associated replies. On success, this returns an HTTP \\`204 No Content\\` response.\n\nComment thread IDs return in the GET comments response for [APIs](https://www.postman.com/postman/workspace/postman-public-workspace/request/12959542-2103ea20-f7de-4628-90e6-b823b3084a52), [collections](https://www.postman.com/postman/workspace/postman-public-workspace/request/12959542-a6582e0a-9382-4760-8b91-53a8aa6cb8d7), and [collection items](https://www.postman.com/postman/workspace/postman-public-workspace/folder/12959542-efeda219-66e1-474c-a83b-253d15723bf7).\n'; +export const parameters = z.object({ + threadId: z.number().int().describe("The comment's thread ID."), +}); +export const annotations = { + title: 'Resolves a comment and any associated replies. On success, this returns an HTTP \\`204 No Content\\` response.\n\nComment thread IDs return in the GET comments response for [APIs](https://www.postman.com/postman/workspace/postman-public-workspace/request/12959542-2103ea20-f7de-4628-90e6-b823b3084a52), [collections](https://www.postman.com/postman/workspace/postman-public-workspace/request/12959542-a6582e0a-9382-4760-8b91-53a8aa6cb8d7), and [collection items](https://www.postman.com/postman/workspace/postman-public-workspace/folder/12959542-efeda219-66e1-474c-a83b-253d15723bf7).\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; +export async function handler(params, extra) { + try { + const endpoint = `/comments-resolutions/${params.threadId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'POST', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/run_monitor.js b/dist/src/tools/run_monitor.js new file mode 100644 index 0000000..c415d99 --- /dev/null +++ b/dist/src/tools/run_monitor.js @@ -0,0 +1,44 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'run-monitor'; +export const description = 'Runs a monitor and returns its run results.\n\n**Note:**\n\n- This endpoint has a timeout restriction of 300 seconds. It is recommended that you include the \\`async=true\\` query parameter when using this endpoint.\n- If you pass the \\`async=true\\` query parameter, the response does not return the \\`stats\\`, \\`executions\\`, and \\`failures\\` responses. To get this information for an asynchronous run, call the GET \\`/monitors/{id}\\` endpoint.\n'; +export const parameters = z.object({ + monitorId: z.string().describe("The monitor's ID."), + async: z + .boolean() + .describe('If true, runs the monitor asynchronously from the created monitor run task. By default, the server will not respond until the task finishes (`false`).') + .default(false), +}); +export const annotations = { + title: 'Runs a monitor and returns its run results.\n\n**Note:**\n\n- This endpoint has a timeout restriction of 300 seconds. It is recommended that you include the \\`async=true\\` query parameter when using this endpoint.\n- If you pass the \\`async=true\\` query parameter, the response does not return the \\`stats\\`, \\`executions\\`, and \\`failures\\` responses. To get this information for an asynchronous run, call the GET \\`/monitors/{id}\\` endpoint.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; +export async function handler(params, extra) { + try { + const endpoint = `/monitors/${params.monitorId}/run`; + const query = new URLSearchParams(); + if (params.async !== undefined) + query.set('async', String(params.async)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'POST', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/sync_collection_with_spec.js b/dist/src/tools/sync_collection_with_spec.js new file mode 100644 index 0000000..ba150a8 --- /dev/null +++ b/dist/src/tools/sync_collection_with_spec.js @@ -0,0 +1,41 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'sync-collection-with-spec'; +export const description = 'Syncs a collection generated from an API specification. This is an asynchronous endpoint that returns an HTTP \\`202 Accepted\\` response.\n\n**Note:**\n\n- This endpoint only supports the OpenAPI 3.0 specification type.\n- You can only sync collections generated from the given spec ID.\n'; +export const parameters = z.object({ + collectionUid: z.string().describe("The collection's unique ID."), + specId: z.string().describe("The spec's ID."), +}); +export const annotations = { + title: 'Syncs a collection generated from an API specification. This is an asynchronous endpoint that returns an HTTP \\`202 Accepted\\` response.\n\n**Note:**\n\n- This endpoint only supports the OpenAPI 3.0 specification type.\n- You can only sync collections generated from the given spec ID.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionUid}/synchronizations`; + const query = new URLSearchParams(); + if (params.specId !== undefined) + query.set('specId', String(params.specId)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/sync_spec_with_collection.js b/dist/src/tools/sync_spec_with_collection.js new file mode 100644 index 0000000..b728fac --- /dev/null +++ b/dist/src/tools/sync_spec_with_collection.js @@ -0,0 +1,41 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'sync-spec-with-collection'; +export const description = 'Syncs an API specification linked to a collection. This is an asynchronous endpoint that returns an HTTP \\`202 Accepted\\` response.\n\n**Note:**\n\n- This endpoint only supports the OpenAPI 3.0 specification type.\n- You can only sync specs generated from the given collection ID.\n'; +export const parameters = z.object({ + specId: z.string().describe("The spec's ID."), + collectionUid: z.string().describe("The collection's unique ID."), +}); +export const annotations = { + title: 'Syncs an API specification linked to a collection. This is an asynchronous endpoint that returns an HTTP \\`202 Accepted\\` response.\n\n**Note:**\n\n- This endpoint only supports the OpenAPI 3.0 specification type.\n- You can only sync specs generated from the given collection ID.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/specs/${params.specId}/synchronizations`; + const query = new URLSearchParams(); + if (params.collectionUid !== undefined) + query.set('collectionUid', String(params.collectionUid)); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/transfer_collection_folders.js b/dist/src/tools/transfer_collection_folders.js new file mode 100644 index 0000000..19c4b1f --- /dev/null +++ b/dist/src/tools/transfer_collection_folders.js @@ -0,0 +1,78 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'transfer-collection-folders'; +export const description = 'Copies or moves folders into a collection or folder.'; +export const parameters = z.object({ + ids: z + .array(z.string()) + .describe('A list of collection request, response, or folder UIDs to transfer.'), + mode: z.enum(['copy', 'move']).describe('The transfer operation to perform.'), + target: z + .object({ + id: z.string().describe('The UID of the destination collection, folder, or request.'), + model: z + .enum(['collection', 'folder', 'request']) + .describe('The collection, folder, or request that the items will be transferred to. For response transfers, use the `request` value.'), + }) + .describe("Information about the item transfer's destination location."), + location: z + .object({ + id: z + .string() + .nullable() + .describe("For `before` or `after` positions, the model's UID.") + .optional(), + model: z + .string() + .nullable() + .describe('For `before` or `after` positions, the type of item (model) that the transferred item will be positioned by. One of: `folder`, `request`, or `response.`\n') + .optional(), + position: z + .enum(['start', 'end', 'before', 'after']) + .describe("The transferred item's position within the destination object.") + .default('end'), + }) + .describe("The transferred items' placement in the target destination:\n- For `start` or `end` โ€” Do not include the `model` and `id` values.\n- For `before` or `after` โ€” Include the `model` and `id` properties.\n"), +}); +export const annotations = { + title: 'Copies or moves folders into a collection or folder.', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collection-folders-transfers`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.ids !== undefined) + bodyPayload.ids = params.ids; + if (params.mode !== undefined) + bodyPayload.mode = params.mode; + if (params.target !== undefined) + bodyPayload.target = params.target; + if (params.location !== undefined) + bodyPayload.location = params.location; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/transfer_collection_requests.js b/dist/src/tools/transfer_collection_requests.js new file mode 100644 index 0000000..9d05ac3 --- /dev/null +++ b/dist/src/tools/transfer_collection_requests.js @@ -0,0 +1,78 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'transfer-collection-requests'; +export const description = 'Copies or moves requests into a collection or folder.'; +export const parameters = z.object({ + ids: z + .array(z.string()) + .describe('A list of collection request, response, or folder UIDs to transfer.'), + mode: z.enum(['copy', 'move']).describe('The transfer operation to perform.'), + target: z + .object({ + id: z.string().describe('The UID of the destination collection, folder, or request.'), + model: z + .enum(['collection', 'folder', 'request']) + .describe('The collection, folder, or request that the items will be transferred to. For response transfers, use the `request` value.'), + }) + .describe("Information about the item transfer's destination location."), + location: z + .object({ + id: z + .string() + .nullable() + .describe("For `before` or `after` positions, the model's UID.") + .optional(), + model: z + .string() + .nullable() + .describe('For `before` or `after` positions, the type of item (model) that the transferred item will be positioned by. One of: `folder`, `request`, or `response.`\n') + .optional(), + position: z + .enum(['start', 'end', 'before', 'after']) + .describe("The transferred item's position within the destination object.") + .default('end'), + }) + .describe("The transferred items' placement in the target destination:\n- For `start` or `end` โ€” Do not include the `model` and `id` values.\n- For `before` or `after` โ€” Include the `model` and `id` properties.\n"), +}); +export const annotations = { + title: 'Copies or moves requests into a collection or folder.', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collection-requests-transfers`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.ids !== undefined) + bodyPayload.ids = params.ids; + if (params.mode !== undefined) + bodyPayload.mode = params.mode; + if (params.target !== undefined) + bodyPayload.target = params.target; + if (params.location !== undefined) + bodyPayload.location = params.location; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/transfer_collection_responses.js b/dist/src/tools/transfer_collection_responses.js new file mode 100644 index 0000000..ad79f34 --- /dev/null +++ b/dist/src/tools/transfer_collection_responses.js @@ -0,0 +1,78 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'transfer-collection-responses'; +export const description = 'Copies or moves responses into a request.'; +export const parameters = z.object({ + ids: z + .array(z.string()) + .describe('A list of collection request, response, or folder UIDs to transfer.'), + mode: z.enum(['copy', 'move']).describe('The transfer operation to perform.'), + target: z + .object({ + id: z.string().describe('The UID of the destination collection, folder, or request.'), + model: z + .enum(['collection', 'folder', 'request']) + .describe('The collection, folder, or request that the items will be transferred to. For response transfers, use the `request` value.'), + }) + .describe("Information about the item transfer's destination location."), + location: z + .object({ + id: z + .string() + .nullable() + .describe("For `before` or `after` positions, the model's UID.") + .optional(), + model: z + .string() + .nullable() + .describe('For `before` or `after` positions, the type of item (model) that the transferred item will be positioned by. One of: `folder`, `request`, or `response.`\n') + .optional(), + position: z + .enum(['start', 'end', 'before', 'after']) + .describe("The transferred item's position within the destination object.") + .default('end'), + }) + .describe("The transferred items' placement in the target destination:\n- For `start` or `end` โ€” Do not include the `model` and `id` values.\n- For `before` or `after` โ€” Include the `model` and `id` properties.\n"), +}); +export const annotations = { + title: 'Copies or moves responses into a request.', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collection-responses-transfers`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.ids !== undefined) + bodyPayload.ids = params.ids; + if (params.mode !== undefined) + bodyPayload.mode = params.mode; + if (params.target !== undefined) + bodyPayload.target = params.target; + if (params.location !== undefined) + bodyPayload.location = params.location; + const result = await fetchPostmanAPI(url, { + method: 'POST', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/unpublish_documentation.js b/dist/src/tools/unpublish_documentation.js new file mode 100644 index 0000000..010e3c1 --- /dev/null +++ b/dist/src/tools/unpublish_documentation.js @@ -0,0 +1,38 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'unpublish-documentation'; +export const description = "Unpublishes a collection's documentation. On success, this returns an HTTP \\`204 No Content\\` response."; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), +}); +export const annotations = { + title: "Unpublishes a collection's documentation. On success, this returns an HTTP \\`204 No Content\\` response.", + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/public-documentations`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/unpublish_mock.js b/dist/src/tools/unpublish_mock.js new file mode 100644 index 0000000..54929aa --- /dev/null +++ b/dist/src/tools/unpublish_mock.js @@ -0,0 +1,36 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'unpublish-mock'; +export const description = 'Unpublishes a mock server. Unpublishing a mock server sets its **Access Control** configuration setting to private.'; +export const parameters = z.object({ mockId: z.string().describe("The mock's ID.") }); +export const annotations = { + title: 'Unpublishes a mock server. Unpublishing a mock server sets its **Access Control** configuration setting to private.', + readOnlyHint: false, + destructiveHint: true, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/mocks/${params.mockId}/unpublish`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'DELETE', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/update_api_collection_comment.js b/dist/src/tools/update_api_collection_comment.js new file mode 100644 index 0000000..b60d076 --- /dev/null +++ b/dist/src/tools/update_api_collection_comment.js @@ -0,0 +1,60 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'update-api-collection-comment'; +export const description = "Updates a comment on an API's collection.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n"; +export const parameters = z.object({ + apiId: z.string().describe("The API's ID."), + collectionId: z.string().describe("The collection's unique ID."), + commentId: z.number().int().describe("The comment's ID."), + body: z.string().describe('The contents of the comment.'), + tags: z + .object({ + '{{userName}}': z + .object({ + type: z.literal('user').describe('The `user` value.'), + id: z.string().describe("The user's ID."), + }) + .describe("An object that contains information about the tagged user. The object's name is the user's Postman username. For example, `@user-postman`.") + .optional(), + }) + .describe('Information about users tagged in the `body` comment.') + .optional(), +}); +export const annotations = { + title: "Updates a comment on an API's collection.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/apis/${params.apiId}/collections/${params.collectionId}/comments/${params.commentId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.body !== undefined) + bodyPayload.body = params.body; + if (params.tags !== undefined) + bodyPayload.tags = params.tags; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/update_collection_comment.js b/dist/src/tools/update_collection_comment.js new file mode 100644 index 0000000..c4e7b24 --- /dev/null +++ b/dist/src/tools/update_collection_comment.js @@ -0,0 +1,59 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'update-collection-comment'; +export const description = 'Updates a comment on a collection.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + commentId: z.number().int().describe("The comment's ID."), + body: z.string().describe('The contents of the comment.'), + tags: z + .object({ + '{{userName}}': z + .object({ + type: z.literal('user').describe('The `user` value.'), + id: z.string().describe("The user's ID."), + }) + .describe("An object that contains information about the tagged user. The object's name is the user's Postman username. For example, `@user-postman`.") + .optional(), + }) + .describe('Information about users tagged in the `body` comment.') + .optional(), +}); +export const annotations = { + title: 'Updates a comment on a collection.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/comments/${params.commentId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.body !== undefined) + bodyPayload.body = params.body; + if (params.tags !== undefined) + bodyPayload.tags = params.tags; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/update_collection_folder.js b/dist/src/tools/update_collection_folder.js new file mode 100644 index 0000000..0a69942 --- /dev/null +++ b/dist/src/tools/update_collection_folder.js @@ -0,0 +1,48 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'update-collection-folder'; +export const description = 'Updates a folder in a collection. For a complete list of properties, refer to the **Folder** entry in the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n\n**Note:**\n\nThis endpoint acts like a PATCH method. It only updates the values that you pass in the request body (for example, the \\`name\\` property). The endpoint does not update the entire resource.\n'; +export const parameters = z.object({ + folderId: z.string().describe("The folder's ID."), + collectionId: z.string().describe("The collection's ID."), + name: z.string().describe("The folder's name.").optional(), + description: z.string().describe("The folder's description.").optional(), +}); +export const annotations = { + title: 'Updates a folder in a collection. For a complete list of properties, refer to the **Folder** entry in the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n\n**Note:**\n\nThis endpoint acts like a PATCH method. It only updates the values that you pass in the request body (for example, the \\`name\\` property). The endpoint does not update the entire resource.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/folders/${params.folderId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.name !== undefined) + bodyPayload.name = params.name; + if (params.description !== undefined) + bodyPayload.description = params.description; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/update_collection_request.js b/dist/src/tools/update_collection_request.js new file mode 100644 index 0000000..b6a5c0a --- /dev/null +++ b/dist/src/tools/update_collection_request.js @@ -0,0 +1,67 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'update-collection-request'; +export const description = 'Updates a request in a collection. For a complete list of properties, refer to the **Request** entry in the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n\n**Note:**\n\n- You must pass a collection ID (\\`12ece9e1-2abf-4edc-8e34-de66e74114d2\\`), not a collection(\\`12345678-12ece9e1-2abf-4edc-8e34-de66e74114d2\\`), in this endpoint.\n- This endpoint does not support changing the folder of a request.\n'; +export const parameters = z.object({ + requestId: z.string().describe("The request's ID."), + collectionId: z.string().describe("The collection's ID."), + name: z.string().describe("The request's name.").optional(), + method: z + .enum([ + 'GET', + 'PUT', + 'POST', + 'PATCH', + 'DELETE', + 'COPY', + 'HEAD', + 'OPTIONS', + 'LINK', + 'UNLINK', + 'PURGE', + 'LOCK', + 'UNLOCK', + 'PROPFIND', + 'VIEW', + ]) + .describe("The request's method.") + .optional(), +}); +export const annotations = { + title: 'Updates a request in a collection. For a complete list of properties, refer to the **Request** entry in the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n\n**Note:**\n\n- You must pass a collection ID (\\`12ece9e1-2abf-4edc-8e34-de66e74114d2\\`), not a collection(\\`12345678-12ece9e1-2abf-4edc-8e34-de66e74114d2\\`), in this endpoint.\n- This endpoint does not support changing the folder of a request.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/requests/${params.requestId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.name !== undefined) + bodyPayload.name = params.name; + if (params.method !== undefined) + bodyPayload.method = params.method; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/update_collection_response.js b/dist/src/tools/update_collection_response.js new file mode 100644 index 0000000..0b98ac8 --- /dev/null +++ b/dist/src/tools/update_collection_response.js @@ -0,0 +1,54 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'update-collection-response'; +export const description = 'Updates a response in a collection. For a complete list of properties, see the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n\n**Note:**\n\n- You must pass a collection ID (\\`12ece9e1-2abf-4edc-8e34-de66e74114d2\\`), not a collection UID (\\`12345678-12ece9e1-2abf-4edc-8e34-de66e74114d2\\`), in this endpoint.\n- This endpoint acts like a PATCH method. It only updates the values that you pass in the request body (for example, the \\`name\\` property). The endpoint does not update the entire resource.\n'; +export const parameters = z.object({ + responseId: z.string().describe("The response's ID."), + collectionId: z.string().describe("The collection's ID."), + name: z.string().describe("The response's name.").optional(), + responseCode: z + .object({ + code: z.number().describe("The response's HTTP response status code.").optional(), + name: z.string().describe('The name of the status code.').optional(), + }) + .describe("The response's HTTP response code information.") + .optional(), +}); +export const annotations = { + title: 'Updates a response in a collection. For a complete list of properties, see the [Postman Collection Format documentation](https://schema.postman.com/collection/json/v2.1.0/draft-07/docs/index.html).\n\n**Note:**\n\n- You must pass a collection ID (\\`12ece9e1-2abf-4edc-8e34-de66e74114d2\\`), not a collection UID (\\`12345678-12ece9e1-2abf-4edc-8e34-de66e74114d2\\`), in this endpoint.\n- This endpoint acts like a PATCH method. It only updates the values that you pass in the request body (for example, the \\`name\\` property). The endpoint does not update the entire resource.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/responses/${params.responseId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.name !== undefined) + bodyPayload.name = params.name; + if (params.responseCode !== undefined) + bodyPayload.responseCode = params.responseCode; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/update_collection_tags.js b/dist/src/tools/update_collection_tags.js new file mode 100644 index 0000000..0f4fcde --- /dev/null +++ b/dist/src/tools/update_collection_tags.js @@ -0,0 +1,57 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'update-collection-tags'; +export const description = "Updates a collection's associated tags. This endpoint replaces all existing tags with those you pass in the request body."; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + tags: z + .array(z + .object({ + slug: z + .string() + .regex(new RegExp('^[a-z][a-z0-9-]*[a-z0-9]+$')) + .min(2) + .max(64) + .describe("The tag's ID within a team or individual (non-team) user scope."), + }) + .describe('Information about the tag.')) + .min(0) + .max(5) + .describe('A list of the associated tags as slugs.'), +}); +export const annotations = { + title: "Updates a collection's associated tags. This endpoint replaces all existing tags with those you pass in the request body.", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/tags`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.tags !== undefined) + bodyPayload.tags = params.tags; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/update_folder_comment.js b/dist/src/tools/update_folder_comment.js new file mode 100644 index 0000000..95605e0 --- /dev/null +++ b/dist/src/tools/update_folder_comment.js @@ -0,0 +1,60 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'update-folder-comment'; +export const description = 'Updates a comment on a folder.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + folderId: z.string().describe("The folder's unique ID."), + commentId: z.number().int().describe("The comment's ID."), + body: z.string().describe('The contents of the comment.'), + tags: z + .object({ + '{{userName}}': z + .object({ + type: z.literal('user').describe('The `user` value.'), + id: z.string().describe("The user's ID."), + }) + .describe("An object that contains information about the tagged user. The object's name is the user's Postman username. For example, `@user-postman`.") + .optional(), + }) + .describe('Information about users tagged in the `body` comment.') + .optional(), +}); +export const annotations = { + title: 'Updates a comment on a folder.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/folders/${params.folderId}/comments/${params.commentId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.body !== undefined) + bodyPayload.body = params.body; + if (params.tags !== undefined) + bodyPayload.tags = params.tags; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/update_mock.js b/dist/src/tools/update_mock.js new file mode 100644 index 0000000..c7db6fb --- /dev/null +++ b/dist/src/tools/update_mock.js @@ -0,0 +1,65 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'update-mock'; +export const description = 'Updates a mock server.'; +export const parameters = z.object({ + mockId: z.string().describe("The mock's ID."), + mock: z + .object({ + name: z.string().describe("The mock server's name.").optional(), + environment: z.string().describe("The associated environment's unique ID.").optional(), + description: z.string().describe("The mock server's description.").optional(), + private: z + .boolean() + .describe('If true, the mock server is set private. By default, mock servers are public and can receive requests from anyone and anywhere.') + .default(false), + versionTag: z.string().describe("The API's version tag ID.").optional(), + config: z + .object({ + serverResponseId: z + .string() + .nullable() + .describe('The server response ID. This sets the given server response as the default response for each request. To deactivate a server response, pass a null value.') + .optional(), + }) + .describe("The mock server's configuration settings.") + .optional(), + }) + .optional(), +}); +export const annotations = { + title: 'Updates a mock server.', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/mocks/${params.mockId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.mock !== undefined) + bodyPayload.mock = params.mock; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/update_monitor.js b/dist/src/tools/update_monitor.js new file mode 100644 index 0000000..03e290f --- /dev/null +++ b/dist/src/tools/update_monitor.js @@ -0,0 +1,142 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'update-monitor'; +export const description = "Updates a monitor's [configurations](https://learning.postman.com/docs/monitoring-your-api/setting-up-monitor/#configure-a-monitor)."; +export const parameters = z.object({ + monitorId: z.string().describe("The monitor's ID."), + monitor: z + .object({ + name: z.string().describe("The monitor's name.").optional(), + active: z + .boolean() + .describe('If true, the monitor is active and makes calls to the specified URL.') + .default(true), + notificationLimit: z + .number() + .gte(1) + .lte(99) + .describe('Stop email notifications after the given number consecutive failures.') + .optional(), + retry: z + .object({ + attempts: z + .number() + .gte(1) + .lte(2) + .describe('The number of times to reattempt a monitor run if it fails or errors. This may impact your [monitor usage](https://learning.postman.com/docs/monitoring-your-api/monitor-usage/#view-monitor-usage).') + .optional(), + }) + .optional(), + options: z + .object({ + followRedirects: z.boolean().describe('If true, follow redirects enabled.').optional(), + requestDelay: z + .number() + .gte(1) + .lte(900000) + .describe("The monitor's request delay value, in milliseconds.") + .optional(), + requestTimeout: z + .number() + .gte(1) + .lte(900000) + .describe("The monitor's request timeout value, in milliseconds.") + .optional(), + strictSSL: z.boolean().describe('If true, strict SSL enabled.').optional(), + }) + .describe("Information about the monitor's option settings.") + .optional(), + schedule: z + .object({ + cron: z + .string() + .describe('The cron expression that defines when the monitor runs. Use standard five-field POSIX cron syntax.\n') + .optional(), + timezone: z + .string() + .describe("The monitor's [timezone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones).") + .optional(), + }) + .describe("Information about the monitor's schedule.") + .optional(), + distribution: z + .array(z.object({ + region: z + .enum([ + 'us-east', + 'us-west', + 'ap-southeast', + 'ca-central', + 'eu-central', + 'sa-east', + 'uk', + 'us-east-staticip', + 'us-west-staticip', + ]) + .describe('The assigned distribution region.') + .optional(), + })) + .describe("A list of the monitor's [geographic regions](https://learning.postman.com/docs/monitoring-your-api/setting-up-monitor/#add-regions).") + .optional(), + notifications: z + .object({ + onError: z + .array(z.object({ + email: z + .string() + .email() + .describe('The email address of the user to notify on monitor error.') + .optional(), + })) + .optional(), + onFailure: z + .array(z.object({ + email: z + .string() + .email() + .describe('The email address of the user to notify on monitor failure.') + .optional(), + })) + .optional(), + }) + .describe("Information about the monitor's notification settings.") + .optional(), + }) + .optional(), +}); +export const annotations = { + title: "Updates a monitor's [configurations](https://learning.postman.com/docs/monitoring-your-api/setting-up-monitor/#configure-a-monitor).", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/monitors/${params.monitorId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.monitor !== undefined) + bodyPayload.monitor = params.monitor; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/update_pan_element_or_folder.js b/dist/src/tools/update_pan_element_or_folder.js new file mode 100644 index 0000000..c0e8a7c --- /dev/null +++ b/dist/src/tools/update_pan_element_or_folder.js @@ -0,0 +1,41 @@ +import { z } from 'zod'; +import { fetchPostmanAPI } from '../clients/postman.js'; +export const method = 'update-pan-element-or-folder'; +export const description = "Updates an element or folder in your team's [Private API Network](https://learning.postman.com/docs/collaborating-in-postman/adding-private-network/).\n\n**Note:**\n\nYou can only pass one element object type per call. For example, you cannot pass both \\`api\\` and \\`collection\\` in a single request.\n"; +export const parameters = z.object({ + elementId: z + .string() + .describe("The element's ID or UUID. For Postman Collections you must pass the collection's UID (`userId`-`collectionId`) value."), + elementType: z.enum(['api', 'folder', 'collection', 'workspace']).describe('The element type.'), +}); +export const annotations = { + title: "Updates an element or folder in your team's [Private API Network](https://learning.postman.com/docs/collaborating-in-postman/adding-private-network/).\n\n**Note:**\n\nYou can only pass one element object type per call. For example, you cannot pass both \\`api\\` and \\`collection\\` in a single request.\n", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/network/private/${params.elementType}/${params.elementId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/update_request_comment.js b/dist/src/tools/update_request_comment.js new file mode 100644 index 0000000..892b739 --- /dev/null +++ b/dist/src/tools/update_request_comment.js @@ -0,0 +1,60 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'update-request-comment'; +export const description = 'Updates a comment on a request.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + requestId: z.string().describe("The request's unique ID."), + commentId: z.number().int().describe("The comment's ID."), + body: z.string().describe('The contents of the comment.'), + tags: z + .object({ + '{{userName}}': z + .object({ + type: z.literal('user').describe('The `user` value.'), + id: z.string().describe("The user's ID."), + }) + .describe("An object that contains information about the tagged user. The object's name is the user's Postman username. For example, `@user-postman`.") + .optional(), + }) + .describe('Information about users tagged in the `body` comment.') + .optional(), +}); +export const annotations = { + title: 'Updates a comment on a request.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/requests/${params.requestId}/comments/${params.commentId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.body !== undefined) + bodyPayload.body = params.body; + if (params.tags !== undefined) + bodyPayload.tags = params.tags; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/update_response_comment.js b/dist/src/tools/update_response_comment.js new file mode 100644 index 0000000..27ec9f1 --- /dev/null +++ b/dist/src/tools/update_response_comment.js @@ -0,0 +1,60 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'update-response-comment'; +export const description = 'Updates a comment on a response.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n'; +export const parameters = z.object({ + collectionId: z.string().describe("The collection's unique ID."), + responseId: z.string().describe("The response's unique ID."), + commentId: z.number().int().describe("The comment's ID."), + body: z.string().describe('The contents of the comment.'), + tags: z + .object({ + '{{userName}}': z + .object({ + type: z.literal('user').describe('The `user` value.'), + id: z.string().describe("The user's ID."), + }) + .describe("An object that contains information about the tagged user. The object's name is the user's Postman username. For example, `@user-postman`.") + .optional(), + }) + .describe('Information about users tagged in the `body` comment.') + .optional(), +}); +export const annotations = { + title: 'Updates a comment on a response.\n\n**Note:**\n\nThis endpoint accepts a max of 10,000 characters.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/collections/${params.collectionId}/responses/${params.responseId}/comments/${params.commentId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.body !== undefined) + bodyPayload.body = params.body; + if (params.tags !== undefined) + bodyPayload.tags = params.tags; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/update_spec_properties.js b/dist/src/tools/update_spec_properties.js new file mode 100644 index 0000000..1ea396e --- /dev/null +++ b/dist/src/tools/update_spec_properties.js @@ -0,0 +1,44 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'update-spec-properties'; +export const description = "Updates an API specification's properties, such as its name."; +export const parameters = z.object({ + specId: z.string().describe("The spec's ID."), + name: z.string().describe("The spec's name."), +}); +export const annotations = { + title: "Updates an API specification's properties, such as its name.", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/specs/${params.specId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.name !== undefined) + bodyPayload.name = params.name; + const result = await fetchPostmanAPI(url, { + method: 'PATCH', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/update_workspace.js b/dist/src/tools/update_workspace.js new file mode 100644 index 0000000..26a3d55 --- /dev/null +++ b/dist/src/tools/update_workspace.js @@ -0,0 +1,54 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'update-workspace'; +export const description = 'Updates a workspace.\n\n**Note:**\n\n- There are rate limits when publishing public workspaces.\n- Public team workspace names must be unique.\n\n### Important\n\nWe deprecated linking collections or environments between workspaces. We do not recommend that you do this.\n\nIf you have a linked collection or environment, note the following:\n- The endpoint does not create a clone of a collection or environment.\n- Any changes you make to a linked collection or environment changes them in all workspaces.\n- If you delete a collection or environment linked between workspaces, the system deletes it in all the workspaces.\n'; +export const parameters = z.object({ + workspaceId: z.string().describe("The workspace's ID."), + workspace: z + .object({ + name: z.string().describe("The workspace's new name.").optional(), + type: z + .enum(['private', 'personal', 'team', 'public']) + .describe('The new workspace visibility [type](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/managing-workspaces/#changing-workspace-visibility). This property does not support the following workspace visibility changes:\n- `private` to `public`, `public` to `private`, and `private` to `personal` for Free and Basic [plans](https://www.postman.com/pricing/).\n- `public` to `personal` for team users.\n') + .optional(), + description: z.string().describe('The new workspace description.').optional(), + about: z.string().describe('A brief summary about the workspace.').optional(), + }) + .optional(), +}); +export const annotations = { + title: 'Updates a workspace.\n\n**Note:**\n\n- There are rate limits when publishing public workspaces.\n- Public team workspace names must be unique.\n\n### Important\n\nWe deprecated linking collections or environments between workspaces. We do not recommend that you do this.\n\nIf you have a linked collection or environment, note the following:\n- The endpoint does not create a clone of a collection or environment.\n- Any changes you make to a linked collection or environment changes them in all workspaces.\n- If you delete a collection or environment linked between workspaces, the system deletes it in all the workspaces.\n', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/workspaces/${params.workspaceId}`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.workspace !== undefined) + bodyPayload.workspace = params.workspace; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/update_workspace_global_variables.js b/dist/src/tools/update_workspace_global_variables.js new file mode 100644 index 0000000..5b01a04 --- /dev/null +++ b/dist/src/tools/update_workspace_global_variables.js @@ -0,0 +1,57 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'update-workspace-global-variables'; +export const description = "Updates and replaces a workspace's global [variables](https://learning.postman.com/docs/sending-requests/variables/#variable-scopes). This endpoint replaces all existing global variables with the variables you pass in the request body."; +export const parameters = z.object({ + workspaceId: z.string().describe("The workspace's ID."), + values: z + .array(z + .object({ + key: z.string().describe("The variable's name.").optional(), + type: z + .enum(['default', 'secret']) + .describe('The [type](https://learning.postman.com/docs/sending-requests/variables/#variable-types) of variable.') + .optional(), + value: z.string().describe("The variable's value.").optional(), + enabled: z.boolean().describe('If true, the variable is enabled.').optional(), + }) + .describe('Information about the global variable.')) + .describe("A list of the workspace's global variables.") + .optional(), +}); +export const annotations = { + title: "Updates and replaces a workspace's global [variables](https://learning.postman.com/docs/sending-requests/variables/#variable-scopes). This endpoint replaces all existing global variables with the variables you pass in the request body.", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/workspaces/${params.workspaceId}/global-variables`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.values !== undefined) + bodyPayload.values = params.values; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +} diff --git a/dist/src/tools/update_workspace_tags.js b/dist/src/tools/update_workspace_tags.js new file mode 100644 index 0000000..3137cbd --- /dev/null +++ b/dist/src/tools/update_workspace_tags.js @@ -0,0 +1,57 @@ +import { z } from 'zod'; +import { fetchPostmanAPI, ContentType } from '../clients/postman.js'; +export const method = 'update-workspace-tags'; +export const description = "Updates a workspace's associated tags. This endpoint replaces all existing tags with those you pass in the request body."; +export const parameters = z.object({ + workspaceId: z.string().describe("The workspace's ID."), + tags: z + .array(z + .object({ + slug: z + .string() + .regex(new RegExp('^[a-z][a-z0-9-]*[a-z0-9]+$')) + .min(2) + .max(64) + .describe("The tag's ID within a team or individual (non-team) user scope."), + }) + .describe('Information about the tag.')) + .min(0) + .max(5) + .describe('A list of the associated tags as slugs.'), +}); +export const annotations = { + title: "Updates a workspace's associated tags. This endpoint replaces all existing tags with those you pass in the request body.", + readOnlyHint: false, + destructiveHint: false, + idempotentHint: true, +}; +export async function handler(params, extra) { + try { + const endpoint = `/workspaces/${params.workspaceId}/tags`; + const query = new URLSearchParams(); + const url = query.toString() ? `${endpoint}?${query.toString()}` : endpoint; + const bodyPayload = {}; + if (params.tags !== undefined) + bodyPayload.tags = params.tags; + const result = await fetchPostmanAPI(url, { + method: 'PUT', + body: JSON.stringify(bodyPayload), + contentType: ContentType.Json, + apiKey: extra.apiKey, + headers: extra.headers, + }); + return { + content: [ + { + type: 'text', + text: `${typeof result === 'string' ? result : JSON.stringify(result, null, 2)}`, + }, + ], + }; + } + catch (e) { + return { + content: [{ type: 'text', text: `Failed: ${e.message}` }], + }; + } +}