home / skills / markus41 / claude / harness-mcp

This skill helps you manage Harness MCP driven CD operations, Git workflows, and Jira synchronization for seamless pipelines.

npx playbooks add skill markus41/claude --skill harness-mcp

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
15.2 KB
---
name: harness-mcp
description: Harness MCP (Model Context Protocol) server integration for AI-powered CD operations, pipeline management, Git repositories, pull requests, code review comments, and bidirectional Jira synchronization
allowed-tools:
  - Bash
  - Read
  - Write
  - Edit
  - Glob
  - Grep
  - Task
  - WebFetch
  - WebSearch
dependencies:
  - harness-cd
  - jira-orchestration
triggers:
  - harness mcp
  - harness ai
  - harness connector
  - harness pipeline
  - harness jira
  - harness git
  - harness pr
  - harness pull request
  - harness repository
  - harness comment
  - harness workspace
  - harness multi-repo
  - harness create repo
  - mcp server
  - cd automation
  - harness confluence
  - documentation sync
  - link confluence
  - readme docs
  - issue documentation
---

# Harness MCP Skill

AI-powered CD operations, Git repository and pull request management via Harness MCP Server.

## Prerequisites

### Environment Variables
```bash
export HARNESS_API_KEY="your-api-key"
export HARNESS_DEFAULT_ORG_ID="your-org-id"
export HARNESS_DEFAULT_PROJECT_ID="your-project-id"
export HARNESS_BASE_URL="https://app.harness.io"
export HARNESS_ACCOUNT_ID="your-account-id"
```

### API Token Generation
1. Navigate to **Account Settings > API Keys** in Harness UI
2. Click **+ API Key**
3. Set permissions (minimum: pipeline execution, connector management)
4. Store securely

## MCP Server Configuration

### Claude Code
```json
{
  "mcpServers": {
    "harness": {
      "command": "npx",
      "args": ["-y", "@anthropic-ai/mcp-harness"],
      "env": {
        "HARNESS_API_KEY": "${HARNESS_API_KEY}",
        "HARNESS_DEFAULT_ORG_ID": "${HARNESS_DEFAULT_ORG_ID}",
        "HARNESS_DEFAULT_PROJECT_ID": "${HARNESS_DEFAULT_PROJECT_ID}",
        "HARNESS_BASE_URL": "${HARNESS_BASE_URL}"
      }
    }
  }
}
```

### Docker
```bash
docker run -e HARNESS_API_KEY=$HARNESS_API_KEY \
           -e HARNESS_DEFAULT_ORG_ID=$HARNESS_DEFAULT_ORG_ID \
           -e HARNESS_DEFAULT_PROJECT_ID=$HARNESS_DEFAULT_PROJECT_ID \
           harness/mcp-server:latest
```

## Available MCP Tools

| Category | Tool | Purpose |
|----------|------|---------|
| **Connectors** | `harness_get_connector`, `harness_list_connectors`, `harness_get_connector_catalogue` | Manage connectors |
| **Pipelines** | `harness_list_pipelines`, `harness_get_pipeline`, `harness_trigger_pipeline` | Pipeline operations |
| **Executions** | `harness_get_execution`, `harness_list_executions`, `harness_get_execution_url` | Track executions |
| **Dashboards** | `harness_list_dashboards`, `harness_get_dashboard` | Dashboard data |
| **Repos** | `harness_get_repository`, `harness_list_repositories` | Repository management |
| **Pull Requests** | `harness_get_pull_request`, `harness_list_pull_requests`, `harness_create_pull_request`, `harness_get_pull_request_checks`, `harness_get_pull_request_activities` | PR operations |

## Git & Pull Request Workflows

### List Repositories
```python
repos = harness_list_repositories(
    org_id="${HARNESS_ORG_ID}",
    project_id="${HARNESS_PROJECT_ID}"
)
```

### Create Pull Request
```python
pr = harness_create_pull_request(
    repo_id="my-application",
    title="PROJ-123: Feature title",
    source_branch="feature/PROJ-123",
    target_branch="main",
    description="## Summary\nImplements feature.\n## Jira\n[PROJ-123](https://company.atlassian.net/browse/PROJ-123)"
)
```

### Get PR Activities (Comments, Reviews)
```python
activities = harness_get_pull_request_activities(repo_id="my-app", pr_number=42)
for activity in activities:
    if activity.type == "comment":
        print(f"Comment by {activity.author} at {activity.file_path}:{activity.line_number}")
    elif activity.type == "review":
        print(f"Review by {activity.author}: {activity.state}")
```

### Sync PR Comments to Jira
```python
activities = harness_get_pull_request_activities(repo_id="my-app", pr_number=42)
review_summary = []
for activity in activities:
    if activity.type == "review":
        review_summary.append(f"- **{activity.author}**: {activity.state}")

jira_add_comment(issue_key="PROJ-123",
    body=f"## PR Review\n**PR:** [#{42}]({pr.url})\n**Status:** {pr.state}\n\n" + "\n".join(review_summary))
```

### PR-to-Jira Status Mapping
```yaml
pr_sync:
  enabled: true
  jira_key_patterns:
    - title: "^([A-Z]+-\\d+)"
    - branch: "feature/([A-Z]+-\\d+)"
  transitions:
    pr_created: { transition: "In Review", comment: "PR created: {pr_url}" }
    pr_approved: { transition: "Approved", comment: "PR approved by {approver}" }
    pr_merged: { transition: "Done", comment: "PR merged to {target_branch}" }
  fields:
    pr_url: "customfield_10200"
    pr_status: "customfield_10201"
    reviewers: "customfield_10202"
```

## Jira Connector Setup

### Create Connector
```yaml
connector:
  name: jira-connector
  identifier: jira_connector
  type: Jira
  spec:
    jiraUrl: https://your-company.atlassian.net
    auth:
      type: UsernamePassword
      spec:
        username: [email protected]
        passwordRef: jira_api_token
    delegateSelectors:
      - delegate-name
```

**Required Scopes:** `read:jira-user`, `read:jira-work`, `write:jira-work`

### Jira Create Step in Pipeline
```yaml
- step:
    name: Create Jira Issue
    type: JiraCreate
    spec:
      connectorRef: jira_connector
      projectKey: PROJ
      issueType: Task
      fields:
        - name: Summary
          value: "Deployment: <+pipeline.name> - <+pipeline.sequenceId>"
        - name: Priority
          value: Medium
```

### Jira Update Step
```yaml
- step:
    name: Update Jira Issue
    type: JiraUpdate
    spec:
      connectorRef: jira_connector
      issueKey: <+pipeline.variables.jiraIssueKey>
      fields:
        - name: Status
          value: Done
      transitionTo:
        transitionName: Done
        status: Done
```

### Jira Approval Step
```yaml
- step:
    name: Jira Approval
    type: JiraApproval
    spec:
      connectorRef: jira_connector
      issueKey: <+pipeline.variables.jiraIssueKey>
      approvalCriteria:
        matchAnyCondition: true
        conditions:
          - key: Status
            operator: equals
            value: Approved
```

## Integration with Jira Orchestrator

### Configuration
```yaml
harness:
  account:
    account_id: "${HARNESS_ACCOUNT_ID}"
    org_id: "${HARNESS_ORG_ID}"
    project_id: "${HARNESS_PROJECT_ID}"
  api:
    base_url: "https://app.harness.io"
    api_key: "${HARNESS_API_KEY}"
  mcp:
    enabled: true
    tools:
      - harness_get_connector
      - harness_list_pipelines
      - harness_get_execution
  jira_connector_ref: "jira_connector"
  sync:
    auto_create_issues: true
    auto_transition: true
    environments:
      dev: "In Development"
      staging: "In QA"
      prod: "Released"
```

### MCP Tool Usage
```python
connector = harness_get_connector(connector_id="jira_connector", org_id="default", project_id="my_project")
executions = harness_list_executions(pipeline_id="deploy_pipeline", limit=10)
execution = harness_get_execution(execution_id="abc123", org_id="default", project_id="my_project")
```

## REST API for PR Operations

### Base URL
```bash
HARNESS_CODE_API="${HARNESS_BASE_URL}/code/api/v1"
```

### Authentication
```bash
curl -H "x-api-key: ${HARNESS_API_KEY}" \
     -H "Content-Type: application/json" \
     "${HARNESS_CODE_API}/repos/{repo-ref}/pullreq/{pr-number}/comments"
```

### Key Endpoints
| Operation | Method | Endpoint |
|-----------|--------|----------|
| Create Comment | POST | `/v1/repos/{repo}/pullreq/{pr}/comments` |
| Create Code Comment | POST | `/v1/repos/{repo}/pullreq/{pr}/comments` (with `path`, `line_start`, `line_end`) |
| Submit Review | POST | `/v1/repos/{repo}/pullreq/{pr}/reviews` |
| Add Reviewer | POST | `/v1/repos/{repo}/pullreq/{pr}/reviewers` |
| Merge PR | POST | `/v1/repos/{repo}/pullreq/{pr}/merge` |

### Create General Comment
```bash
curl -X POST "${HARNESS_CODE_API}/repos/${REPO}/pullreq/${PR}/comments" \
  -H "x-api-key: ${HARNESS_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"text": "Great work!"}'
```

### Create Code Comment
```bash
curl -X POST "${HARNESS_CODE_API}/repos/${REPO}/pullreq/${PR}/comments" \
  -H "x-api-key: ${HARNESS_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Consider adding null check",
    "path": "src/auth.ts",
    "line_start": 42,
    "line_end": 45,
    "line_start_new": true,
    "line_end_new": true
  }'
```

### Submit Review
```bash
curl -X POST "${HARNESS_CODE_API}/repos/${REPO}/pullreq/${PR}/reviews" \
  -H "x-api-key: ${HARNESS_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"commit_sha": "abc123", "decision": "approved"}'
```

**Decision Values:** `approved`, `changereq`, `reviewed`

### Merge PR
```bash
curl -X POST "${HARNESS_CODE_API}/repos/${REPO}/pullreq/${PR}/merge" \
  -H "x-api-key: ${HARNESS_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "method": "squash",
    "source_sha": "abc123",
    "title": "feat: Add auth",
    "delete_source_branch": true
  }'
```

**Merge Methods:** `merge`, `squash`, `rebase`, `fast-forward`

## Bash Helper Functions

```bash
export HARNESS_CODE_API="${HARNESS_BASE_URL:-https://app.harness.io}/code/api/v1"

harness_pr_comment() {
  local repo="$1" pr="$2" text="$3"
  curl -s -X POST "${HARNESS_CODE_API}/repos/${repo}/pullreq/${pr}/comments" \
    -H "x-api-key: ${HARNESS_API_KEY}" \
    -H "Content-Type: application/json" \
    -d "{\"text\": \"${text}\"}"
}

harness_pr_approve() {
  local repo="$1" pr="$2" commit_sha="$3"
  curl -s -X POST "${HARNESS_CODE_API}/repos/${repo}/pullreq/${pr}/reviews" \
    -H "x-api-key: ${HARNESS_API_KEY}" \
    -H "Content-Type: application/json" \
    -d "{\"commit_sha\": \"${commit_sha}\", \"decision\": \"approved\"}"
}

harness_pr_merge() {
  local repo="$1" pr="$2" method="${3:-squash}" source_sha="$4" title="$5"
  curl -s -X POST "${HARNESS_CODE_API}/repos/${repo}/pullreq/${pr}/merge" \
    -H "x-api-key: ${HARNESS_API_KEY}" \
    -H "Content-Type: application/json" \
    -d "{\"method\": \"${method}\", \"source_sha\": \"${source_sha}\", \"title\": \"${title}\", \"delete_source_branch\": true}"
}
```

## Python Client

```python
import requests, os
from typing import Optional, Literal

class HarnessCodeAPI:
    def __init__(self, api_key: str = None, base_url: str = None):
        self.api_key = api_key or os.environ.get("HARNESS_API_KEY")
        self.base_url = base_url or os.environ.get("HARNESS_BASE_URL", "https://app.harness.io")
        self.api_url = f"{self.base_url}/code/api/v1"
        self.headers = {"x-api-key": self.api_key, "Content-Type": "application/json"}

    def create_comment(self, repo: str, pr_number: int, text: str, path: Optional[str] = None,
                      line_start: Optional[int] = None, line_end: Optional[int] = None,
                      parent_id: Optional[int] = None) -> dict:
        url = f"{self.api_url}/repos/{repo}/pullreq/{pr_number}/comments"
        data = {"text": text}
        if parent_id:
            data["parent_id"] = parent_id
        elif path and line_start:
            data.update({"path": path, "line_start": line_start, "line_end": line_end or line_start,
                        "line_start_new": True, "line_end_new": True})
        return requests.post(url, headers=self.headers, json=data).json()

    def submit_review(self, repo: str, pr_number: int, commit_sha: str,
                     decision: Literal["approved", "changereq", "reviewed"]) -> dict:
        url = f"{self.api_url}/repos/{repo}/pullreq/{pr_number}/reviews"
        data = {"commit_sha": commit_sha, "decision": decision}
        return requests.post(url, headers=self.headers, json=data).json()

    def approve(self, repo: str, pr_number: int, commit_sha: str) -> dict:
        return self.submit_review(repo, pr_number, commit_sha, "approved")

    def merge(self, repo: str, pr_number: int, source_sha: str,
             method: Literal["merge", "squash", "rebase", "fast-forward"] = "squash",
             title: Optional[str] = None, delete_source_branch: bool = True,
             dry_run: bool = False) -> dict:
        url = f"{self.api_url}/repos/{repo}/pullreq/{pr_number}/merge"
        data = {"method": method, "source_sha": source_sha, "delete_source_branch": delete_source_branch, "dry_run": dry_run}
        if title:
            data["title"] = title
        return requests.post(url, headers=self.headers, json=data).json()
```

## Multi-Repository Workspace Support

### Configuration
```yaml
harness:
  workspace:
    repositories:
      - identifier: frontend-app
        path: ./frontend
        jira_project: FRONT
      - identifier: backend-api
        path: ./backend
        jira_project: BACK
    auto_create_repos: true
    default_branch: main
  review:
    cross_repo_review: true
  jira:
    sync_enabled: true
    aggregate_prs: true
```

### Python API
```python
from lib.harness_code_api import HarnessCodeAPI

client = HarnessCodeAPI()
repos = client.setup_workspace_repos([
    {"identifier": "frontend", "path": "./frontend"},
    {"identifier": "backend", "path": "./backend"}
])
prs = client.get_workspace_prs(repo_identifiers=["frontend", "backend"], state="open", jira_key="PROJ-123")
```

## Repository Creation

### Python
```python
repo = client.create_repository(
    identifier="my-service",
    description="User management service",
    default_branch="main",
    is_public=False,
    readme=True,
    license="MIT"
)
```

### REST API
| Operation | Method | Endpoint |
|-----------|--------|----------|
| List Repos | GET | `/v1/repos` |
| Get Repo | GET | `/v1/repos/{repo}` |
| Create Repo | POST | `/v1/repos` |
| Update Repo | PATCH | `/v1/repos/{repo}` |
| Delete Repo | DELETE | `/v1/repos/{repo}` |

## Confluence Documentation Integration

### Auto-Documentation
```python
from lib.confluence_doc_linker import ConfluenceDocLinker

linker = ConfluenceDocLinker()
docs = linker.ensure_issue_docs("PROJ-123")
linker.link_readme_to_confluence(readme_path="./README.md", jira_key="PROJ-123")
```

### Configuration
```yaml
documentation:
  confluence:
    base_url: "${CONFLUENCE_BASE_URL}"
    space_key: "ENG"
  auto_create:
    enabled: true
    on_work_start: true
  readme:
    auto_update: true
```

## Troubleshooting

| Issue | Solution |
|-------|----------|
| Invalid API Key | Regenerate in Harness UI |
| Network timeout | Check delegate connectivity |
| Permission denied | Verify API key permissions |
| Jira unreachable | Check firewall/proxy |

### Debug Logging
```bash
export HARNESS_LOG_LEVEL=debug
export MCP_DEBUG=true
```

## Best Practices

1. Use Harness Secrets for credentials
2. Select delegates with direct Jira network access
3. Configure error handling with retries
4. Enable logging for all operations
5. Scope API tokens to minimum permissions

## Related Resources

- [Harness MCP Server](https://developer.harness.io/docs/platform/harness-aida/harness-mcp-server/)
- [Harness Code Repository](https://developer.harness.io/docs/code-repository/)
- [PR Review](https://developer.harness.io/docs/code-repository/pull-requests/review-pr/)
- [PR Merge](https://developer.harness.io/docs/code-repository/pull-requests/merge-pr/)
- [Jira Connector Setup](https://developer.harness.io/docs/platform/connectors/ticketing-systems/connect-to-jira/)
- [Jira Steps in CD](https://developer.harness.io/docs/continuous-delivery/x-platform-cd-features/cd-steps/ticketing-systems/create-jira-issues-in-cd-stages/)

Overview

This skill integrates Harness MCP (Model Context Protocol) server capabilities to manage CD operations, pipelines, Git repositories, pull requests, code review comments, and bidirectional Jira synchronization. I provide tools and helpers for triggering pipelines, inspecting executions, managing connectors, performing PR workflows, and syncing PR state and comments with Jira. The skill is designed for automation in CI/CD and developer workflow orchestration.

How this skill works

I expose MCP tools and REST endpoints to list and manipulate connectors, pipelines, executions, repositories, and pull requests. The integration uses a Harness API key and org/project context to call the Harness Code API for comments, reviews, merges, and repository management. I also offer Jira connector configuration and pipeline steps to create, update, and transition Jira issues automatically based on PR and pipeline events.

When to use it

  • Automate pipeline triggers and monitor execution status programmatically.
  • Manage repositories and create or merge pull requests from automation scripts.
  • Sync PR comments, reviews, and status into Jira issues for traceability.
  • Create or update Jira issues from pipeline steps or deployment events.
  • Aggregate and review cross-repo pull requests in multi-repository workspaces.

Best practices

  • Store HARNESS_API_KEY and Jira credentials in a secrets manager; avoid plain env vars in shared scripts.
  • Grant minimal API token scopes: pipeline execution, connector management, and code operations.
  • Use delegate selectors with direct network access to Jira to avoid connectivity issues.
  • Enable debug logging (HARNESS_LOG_LEVEL=debug, MCP_DEBUG=true) when troubleshooting.
  • Map PR lifecycle events to Jira transitions and custom fields for consistent audit trails.

Example use cases

  • Trigger a deploy pipeline and post the execution URL to the related Jira issue automatically.
  • Create a pull request with a Jira key in the title and sync reviewers and comments back to the issue.
  • Collect PR review summaries and add them as comments to the matching Jira ticket.
  • Approve and merge PRs programmatically after automated checks pass using the Code API.
  • Configure a multi-repo workspace to aggregate open PRs for a single Jira epic or ticket.

FAQ

What credentials are required to use this integration?

You need a Harness API key with pipeline and connector permissions, plus a Jira connector (username+API token) with read/write scopes for work and users.

How does PR-to-Jira synchronization identify the Jira issue?

Synchronization uses configurable regex patterns on PR titles and branch names to extract Jira keys, and maps PR events to Jira transitions and custom fields.