> For the complete documentation index, see llms.txt.
Skip to main content

Check out Port for yourself ➜ 

Sync Port configurations between environments using Port AI and MCP

This guide shows how to move Port configurations between environments by using GitHub as your source of truth. We will connect GitHub MCP, register a reusable skill for configuration export and import, back up blueprints and actions into a repository, and then import them into a second Port environment.

Banner image

Common use cases

  • Environment migration: Move data model changes from a staging environment to a production environment in a controlled flow.
  • Configuration backup: Keep a versioned backup of blueprints and actions in GitHub.
  • Cross-region setup: Sync configuration between separate Port organizations, such as US and EU environments.

Prerequisites

This guide assumes you have:

  • Two Port environments with MCP enabled.
  • Access to a GitHub repository that will store backup files, such as port-configuration.
  • Cursor IDE installed and authenticated to both Port environments.
  • A Skills blueprint configured in Port. You can follow Create custom skills.

Connect GitHub MCP

We want to use GitHub as the central source of truth for configuration files.

  1. Go to your Developer portal.

  2. Click your avatar in the top-right corner.

  3. Select MCP Servers.

  4. Open the MCP External tab.

  5. Connect GitHub by following GitHub MCP connector.

  6. Repeat the same flow in your second Port environment.

    Connected Github MCP

After connecting GitHub, confirm these tools are enabled in each environment:

  • Repository search.
  • Branch creation.
  • Pull request creation.
  • File create and update.
  • Multi-file push.
  • Pull request read and status tools.

Create the backup skill

Create this skill in the environment where you plan to run backup and import prompts. If you want identical behavior in both environments, register the skill in both.

  1. Go to the Skill catalog page.
  2. Click + Skill.
  3. Enable JSON Mode.
  4. Paste the entity below.
  5. Click Register.
Manage Port configuration skill entity (click to expand)
{
"identifier": "manage_port_configuration",
"title": "Manage Port Configuration",
"icon": "Port",
"properties": {
"description": "Import, export, or diff Port configuration objects (blueprints, actions, or both) to/from a GitHub repository. Use when the user wants to sync Port config with a repo, back up blueprints/actions, restore them from source control, or check for differences (drift) between the live Port configuration and the files stored in a GitHub backup.",
"instructions": "You are a Port configuration manager. Follow these steps based on the requested operation.\n\n## Inputs to collect\nBefore starting, ensure you have:\n- **repository**: GitHub repo in `org/repo` format\n- **config_type**: one of `blueprints`, `actions`, or `both`\n- **operation**: one of `import`, `export`, or `diff`\n\n---\n\n## EXPORT - Port -> GitHub\n\n### Branch\n- **Never push directly to `main` (or `master`).** Always create a timestamped side branch first:\n `port/export-<config_type>-YYYYMMDD-HHMMSS`\n Example: `port/export-actions-20260325-153000`\n- Use `github_create_branch` to create the branch from `main` before writing any files.\n\n### Blueprints (if config_type is `blueprints` or `both`)\n1. Call `list_blueprints` (no identifiers) to get all blueprint summaries.\n2. For each blueprint, call `list_blueprints` with its identifier to get the full schema.\n3. **Sanitize meta properties** - before writing, strip the following read-only fields from each blueprint object:\n - `createdAt`, `updatedAt`, `createdBy`, `updatedBy`\n - `id`, `organization`\n - Any field prefixed with `_` that is not part of the user-defined schema\n4. Write the sanitized JSON to `port/blueprints/<identifier>.json` on the side branch using `github_create_or_update_file`.\n\n### Actions (if config_type is `actions` or `both`)\n1. Call `list_actions` to retrieve all actions.\n2. **Sanitize meta properties** - before writing, strip the following read-only fields from each action object:\n - `createdAt`, `updatedAt`, `createdBy`, `updatedBy`\n - `id`, `organization`\n - Any field prefixed with `_` that is not part of the user-defined action definition\n3. Write the sanitized JSON to `port/actions/<identifier>.json` on the side branch using `github_create_or_update_file`.\n\n### Pull request\n- After all files are written, open a pull request from the side branch into `main` using `github_create_pull_request`.\n- PR title: `chore: export Port configuration (<config_type>) - <date>`.\n- PR body should list all exported resources (type | identifier).\n- **Return the PR URL to the user.**\n\n---\n\n## IMPORT - GitHub -> Port\n\n> **Source of truth: `main` branch only.**\n> Always read from the `main` branch, regardless of any open export PRs or side branches. Export branches are staging areas and are never considered a valid source for import.\n\n### Blueprints (if config_type is `blueprints` or `both`)\n1. Use `github_get_file_contents` to list and read all files under `port/blueprints/` in the repository, **explicitly passing `branch: main`**.\n2. Parse each JSON file as a blueprint definition.\n3. **Sanitize meta properties** - before upserting, strip any read-only meta fields:\n - `createdAt`, `updatedAt`, `createdBy`, `updatedBy`\n - `id`, `organization`\n - Any field prefixed with `_` that is not part of the user-defined schema\n4. Call `upsert_blueprint` for each sanitized definition.\n\n### Actions (if config_type is `actions` or `both`)\n1. Use `github_get_file_contents` to list and read all files under `port/actions/` in the repository, **explicitly passing `branch: main`**.\n2. Parse each JSON file as an action definition.\n3. **Sanitize meta properties** - before upserting, strip any read-only meta fields:\n - `createdAt`, `updatedAt`, `createdBy`, `updatedBy`\n - `id`, `organization`\n - Any field prefixed with `_` that is not part of the user-defined action definition\n4. Call `upsert_action` for each sanitized definition.\n\n### Report\n- After all upserts, output a summary table: resource type | identifier | result (created / updated / failed).\n- For any failures, include the error message.\n\n---\n\n## DIFF - Compare Port (live) vs GitHub (backup)\n\nThis operation detects drift between what is currently in Port and what is stored in the GitHub backup files. It does **not** make any changes.\n\n> **Source of truth: `main` branch only.**\n> Always read from the `main` branch, regardless of any open export PRs or side branches. A pending export PR has not been reviewed or merged and does not represent the approved backup state.\n\n### Fetch live configuration from Port\n\n**Blueprints** (if config_type is `blueprints` or `both`):\n1. Call `list_blueprints` (no identifiers) to get all blueprint summaries.\n2. For each blueprint, call `list_blueprints` with its identifier to get the full schema.\n3. Sanitize meta properties (strip `createdAt`, `updatedAt`, `createdBy`, `updatedBy`, `id`, `organization`, and any `_`-prefixed system fields).\n\n**Actions** (if config_type is `actions` or `both`):\n1. Call `list_actions` to retrieve all actions.\n2. Sanitize meta properties the same way.\n\n### Fetch backup configuration from GitHub (`main` branch)\n\n**Blueprints** (if config_type is `blueprints` or `both`):\n1. Use `github_get_file_contents` to list and read all files under `port/blueprints/` in the repository, **explicitly passing `branch: main`**.\n2. Parse each JSON file and sanitize the same meta properties.\n\n**Actions** (if config_type is `actions` or `both`):\n1. Use `github_get_file_contents` to list and read all files under `port/actions/` in the repository, **explicitly passing `branch: main`**.\n2. Parse each JSON file and sanitize the same meta properties.\n\n### Compare and report\n\nFor each resource type (blueprints and actions), produce a diff report:\n\n1. **Only in Port (not in backup)** - present in Port but no corresponding file on `main`.\n2. **Only in backup (not in Port)** - file exists on `main` but resource is missing from Port.\n3. **Present in both but different** - sanitized JSON does not match. List each differing field path with Port value vs backup value.\n4. **In sync** - sanitized JSON is identical in both.\n\n### Output format\n\n```\n## Port configuration diff report\nRepository: <org/repo>\nBranch: main\nConfig type: <blueprints | actions | both>\nDate: <current date>\n\n### Blueprints\n| Status | Identifier | Details |\n|--------|------------|---------|\n| Only in Port | my-blueprint | Not found in backup |\n| Only in backup | old-blueprint | File: port/blueprints/old-blueprint.json |\n| Differs | service | 3 field(s) changed (see below) |\n| In sync | environment | ✓ |\n\n#### Differences - service\n- `schema.properties.status.enum`: Port=[\"Active\",\"Inactive\"] vs Backup=[\"Active\",\"Deprecated\",\"Inactive\"]\n- `relations.team.required`: Port=false vs Backup=true\n\n### Actions\n...\n\n### Summary\n- X resource(s) only in Port.\n- X resource(s) only in backup.\n- X resource(s) with differences.\n- X resource(s) in sync.\n```\n\n- **Do not make any changes to Port or GitHub** during a diff operation.\n- If a backup file is malformed or unparseable, report it as an error in the diff output.\n\n---\n\n## General rules\n- **Never push directly to `main` or `master`.** All writes go to a timestamped side branch (export only).\n- **Import and diff always read from `main`.** Never read from export side branches or open PRs.\n- Never delete existing Port resources unless the user explicitly asks.\n- If a file is malformed or fails sanitization, skip it and report it as failed. Do not abort the entire operation.\n- Always confirm the final count of successfully processed resources and share the PR URL at the end (export only)."
},
"relations": {}
}

Connect Port environments to Cursor

Add both environments as MCP servers in Cursor:

{
"mcpServers": {
"port-source-env": {
"url": "https://mcp.port.io/v1",
"headers": {
"x-read-only-mode": "0"
}
},
"port-target-env": {
"url": "https://mcp.port.io/v1",
"headers": {
"x-read-only-mode": "0"
}
}
}
}
Port US Data Center

Use https://mcp.us.port.io/v1 if your Port data center is in the US.

After adding both servers, authenticate each one from Cursor so both are available in chat.

Back up configurations to GitHub from source environment

Start in Cursor with a prompt like this:

Use the port-source-env MCP server to create a PR in the <port-configuration> repository, backing up all the Wiz blueprints JSON. Make sure to load the right skill for this task.
Variable Replacement

Make sure to replace <port-configuration> with your desired repository

You can change the resource scope from PagerDuty blueprints to:

  • Pagerduty blueprints.
  • All blueprints.
  • Actions only.
  • Both blueprints and actions.

Expected result:

  • Cursor loads manage_port_configuration.

  • A branch is created in GitHub.

  • Backup files are written under port/blueprints/ and or port/actions/.

  • A pull request URL is returned.

    Cursor chat exporting Port configurations to Github Cursor chat exporting Port configurations to Github

Merge the backup pull request

Open the pull request in GitHub, review the exported files, and merge it into main. The skill reads only from main for import, so this merge step is required:

Github Pull request with Wiz blueprint backup

Import configurations into target environment

Go back to Cursor and run an import prompt like this:

I've merged the PR. Now import all the Wiz blueprints back into the port-target-env MCP.

Expected result:

  • Cursor reads configuration files from main.

  • Cursor upserts each resource into port-target-env.

  • Cursor returns a summary of created, updated, and failed resources.

    Cursor chat importing Port configurations Cursor chat importing Port configurations
Skill availability in target environment

If manage_port_configuration is missing in the target environment, register the same skill there, or instruct Cursor to load the skill from the source environment and run upserts against the target server.

Validate configuration sync

Visit your target environment in Port to confirm that the blueprints or actions have been created as expected.

Created Wiz blueprints in Port

By following these steps, you can confidently migrate Port configurations between environments. This approach ensures reliable versioning, easy recovery, and helps maintain consistency across your different Port instances.