> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Demo Connecting an MCP Server

> Demo of connecting an assistant to GitHub via an MCP server to fetch issues and logs, run a triage runbook, and post comments or escalation issues

Welcome to this demo. Here we show how to give an assistant access to GitHub using an MCP (Model‑Connected Protocol) server so it can fetch issues and logs, triage them using a runbook, and write results back into the repository (for example: issue comments and escalation issues).

Overview

* Historically, help‑desk AI required a human to paste logs into a chat. The agent could read them and reply, but output stayed in a terminal or operator app.
* With MCP, you replace individual integrations with a single standard: a host (your script) runs a client that connects to an MCP server which exposes tools (issue\_read, get\_file\_contents, add\_issue\_comment, issue\_write, …). The model discovers the server’s tools and uses them directly — no bespoke API client needed.

Scenario

* Same assistant behavior as before: triage a ticket and follow the runbook.
* Change: tickets are GitHub issues. Logs live in files in the same repository. The model:
  1. fetches the issue,
  2. reads the log file referenced in the Tier 1 notes (use the exact path),
  3. analyzes the logs,
  4. posts a triage comment,
  5. creates an escalation issue only when the runbook requires it.

Example ticket (excerpt)

```text theme={null}
**Ticket #48213** - VPN: "Connection rejected by policy (0x4C)"
**Opened:** 2026-09-21 08:19 ET
**Requester:** Dana Whitfield (dwhitfield), Regional Sales, remote (home office)
**Device:** BWL-LT-4471, MacBook Pro, macOS 15.6
**Priority:** High (customer calls start at 9:00)

**User's description:**
"I can't get on the VPN this morning. I type my password, I approve the push on my phone, then it sits for a few seconds and shows 'Connection rejected by policy (0x4C)' and disconnects."

**Tier 1 agent notes:**
Pulled the vpn-gw-01 log for 2026-09-21 03:00-08:15, filtered to user=dwhitfield plus the surrounding entries, and committed the excerpt to `logs/vpn-gw-01/2026-09-21.log` in this repository.

**Tier 1 update (08:31 ET):** Walked Dana through Self Service while waiting on triage. It does not list a BWL Endpoint Agent update; the installed agent shows 5.2.1.
```

What changed for the assistant

* The assistant receives a one‑line request naming the repo and issue ID. Example:

```text theme={null}
Ticket #48213 for Dana Whitfield (dwhitfield) is open as issue #1 in the `btkrausen/brightwater-helpdesk` repository. Please triage it.
```

* The model must:
  * fetch the issue,
  * fetch the exact file path mentioned in the Tier 1 notes,
  * analyze the log excerpt,
  * post the triage comment,
  * create an escalation issue only when the runbook requires it.

System prompt / instructions (excerpt)

```text theme={null}
You are HelpDesk AI, the internal IT support assistant at Brightwater Logistics. You work alongside Tier 1 support agents. Tickets are GitHub issues in repositories.

WHAT YOU WILL RECEIVE
- A short request naming the ticket: the repository and the issue number. Nothing is pasted for you.
- Use your tools to fetch the ticket first, then the log excerpt the Tier 1 notes point to. Use the exact file path given in the ticket; do not guess.
- The ticket tells you who the user is, what device they are on, what they tried, and what they saw. The log excerpt holds lines from the system involved.

HOW TO WORK
1. Read the ticket first. Note the user ID, device name, time window, and the exact error text the user reported.
2. Search the log excerpt for entries that match that user, device, or time window.
3. Decide on a root cause only if the log lines support it. Quote the exact lines (timestamp and message) that prove it. Two or more matching attempts are best evidence.
4. If the logs do not explain the problem, say so plainly and name the single log source or piece of information that would settle it. Do not guess.
5. Match the root cause to a runbook entry below and give the Tier 1 fix from that entry. If no entry matches, write "No runbook entry" and escalate.
6. Never ask the user for a password. Never recommend a password reset unless the logs show a credential failure (AUTH_RADIUS result=REJECT or result=LOGIN_FAILURE).
7. Do not invent hostnames, policy names, version numbers, or error codes. Use only what appears in the ticket, the logs, or this runbook.
8. Write for a Tier 1 agent who is on the phone with the user: short sentences, no jargon that is not already in the ticket.
9. When the triage is complete, act on it with your tools, in this order:
   a. Post the triage as a comment on the ticket, using the output format below.
   b. If the runbook entry says to escalate, open one new issue in the same repository titled `Escalation: <team> - <one line>`, with the labels `escalation` and the receiving team's label.
   c. Then give the same five headings as your final reply for the Tier 1 agent on the phone.

OUTPUT FORMAT

Use exactly these five headings, in this order, and nothing else:
- Summary
- Root cause
- Fix
- Escalate to
- Confidence
```

VPN troubleshooting runbook (Tier 1) — excerpt

```text theme={null}
R1. Password rejected.
    Log shows: AUTH_RADIUS result=REJECT
    Fix: Confirm the user is typing their network password, not their email password. Three rejects -> escalate.

R2. MFA push never arrives or times out.
    Log shows: MFA_PUSH_SENT followed by MFA_PUSH_TIMEOUT
    Fix: Ask which phone received the push. If the user changed phones, check MFA device registration.

R3. Connection rejected by policy (client shows error 0x4C).
    Log shows: POSTURE_CHECK result=FAIL with a reason field. Reason tells you which device check failed:
      - agent_version_below_minimum: BWL Endpoint Agent on device is older than policy requires. Have the user open Self Service and install the update if listed, or escalate if not.
      - disk_encryption_not_reported: FileVault or BitLocker status not reported. Have the user open the BWL Endpoint Agent, click "Sync now", wait two minutes, and retry.
      - os_build_below_minimum: OS needs updates. Have the user run OS updates, reboot, and reconnect.

R4. Client shows "update required".
    Log shows: CLIENT VERSION REJECT
    Fix: Have the user install the current BrightConnect VPN client from Self Service.

R5. Connects, then drops every few minutes.
    Log shows: SESSION_CLOSE reason=keepalive_timeout
    Fix: Likely home Wi‑Fi or a captive portal. Ask the user to try a mobile hotspot.

R6. Connected, but internal sites do not resolve by name.
    Log shows: SESSION_OPEN with dns_push=ok
    Fix: Have the user disconnect, flush DNS, and reconnect.

R7. "No addresses available" or hangs at "Assigning address".
    Log shows: IP_POOL result=EXHAUSTED
    Fix: Escalate to NetOps.
```

How the GitHub MCP server fits

* The MCP server exposes a set of tools (for example: `issue_read`, `get_file_contents`, `add_issue_comment`, `issue_write`). The model sees these tool definitions as part of its context and can call them directly.
* The host (your script) launches the MCP server locally (binary or Docker) and connects over stdio using JSON‑RPC.
* The MCP server authenticates to GitHub using a personal access token provided via environment variable (`GITHUB_PERSONAL_ACCESS_TOKEN`).

<Callout icon="lightbulb" color="#1CB2FE">
  Store `GITHUB_PERSONAL_ACCESS_TOKEN` in your environment as a fine‑grained token scoped only to the demo repo. Never hardcode tokens in scripts.
</Callout>

<Callout icon="warning" color="#FF6B6B">
  Use a fine‑grained GitHub token scoped only to the repository and the exact tool permissions you need. Do not grant broad organization rights or hardcode tokens in source control.
</Callout>

Running the GitHub MCP server (example)

* On macOS you can install the official binary (Homebrew) and run:

```bash theme={null}
github-mcp-server stdio --toolsets context,repos,issues
```

Example server start log (trimmed and corrected):

```text theme={null}
time=2026-09-22T10:27:32.081-04:00 level=INFO msg="starting server" version=1.12.2 readOnly=false lockdownEnabled=false
GitHub MCP Server running on stdio
time=2026-09-22T10:27:32.087-04:00 level=INFO msg="server run start"
time=2026-09-22T10:27:32.088-04:00 level=INFO msg="server session connected" session_id=""
```

How the host launches the server (Python excerpt)

* The host decides whether to run the binary directly or via Docker, then launches the MCP server with the requested `--toolsets`. The host passes the `GITHUB_PERSONAL_ACCESS_TOKEN` via the environment.

```python theme={null}
# server_params: construct how to run the GitHub MCP server for this host
import os
import sys
from pathlib import Path

TOOLSETS = "context,repos,issues"
here = Path(__file__).resolve().parent

def server_params(args):
    token = os.environ.get("GITHUB_PERSONAL_ACCESS_TOKEN")
    if not token:
        sys.exit("Set GITHUB_PERSONAL_ACCESS_TOKEN to a fine-grained token for the demo repo first.")
    flags = ["--toolsets", TOOLSETS] + (["--read-only"] if getattr(args, "read_only", False) else [])
    if getattr(args, "docker", False):
        return {
            "command": "docker",
            "args": ["run", "-i", "--rm", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN",
                     "ghcr.io/github/github-mcp-server", "stdio", *flags],
            "env": {"GITHUB_PERSONAL_ACCESS_TOKEN": token},
        }

    return {
        "command": "github-mcp-server",      # brew install github-mcp-server
        "args": ["stdio", *flags,            # stdio = server talks JSON-RPC over stdin/stdout
                 "--log-file", str(here / ".github-mcp-server.log")],
        "env": {"GITHUB_PERSONAL_ACCESS_TOKEN": token},
    }
```

Discovering tools and adapting them for the model

```python theme={null}
# discover_tools: page through mcp.list_tools to collect available tools
async def discover_tools(mcp):
    tools = []
    cursor = None
    while True:
        page = await mcp.list_tools(cursor=cursor)
        tools.extend(page.tools)
        cursor = page.next_cursor
        if not cursor:
            break
    return tools

def as_model_tools(mcp_tools):
    """Convert MCP tool definitions into the model's tool list: name, description, input_schema."""
    return [
        {"name": t.name, "description": t.description or "", "input_schema": t.input_schema}
        for t in mcp_tools
    ]
```

Flattening server results to text the model can read

```python theme={null}
def result_text(result):
    parts = []
    for block in result.content:
        # TextContent, CodeContent, etc. — keep this implementation aligned with the MCP SDK you're using
        if isinstance(block, TextContent):
            parts.append(block.text)
        elif isinstance(block, CodeContent):
            parts.append(block.code)
    return "\n\n".join(parts)
```

Common toolsets to expose (recommendation)

| Toolset | Purpose | Example |
| - | - | - |
| context | Provide model with runtime context and metadata | `context` |
| repos | Repository read/write operations | `repos` |
| issues | Read and modify GitHub Issues (comments, create issues) | `issues` |

Note: Limit the toolsets to only what you need (`context,repos,issues`) to reduce the model’s action surface.

Listing tools (host runs agent with `--list-tools`)

* Running the local agent with `--list-tools` launches the MCP server, discovers the tools, and prints them. Example:

```bash theme={null}
python3 run_agent.py --list-tools
```

Trimmed example output:

```text theme={null}
Launching MCP server: github-mcp-server stdio --toolsets context,repos,issues --log-file /.../.github-mcp-server.log
GitHub MCP Server running on stdio
Discovered 32 tools from the server (none written by us):
    add_issue_comment, create_branch, create_or_update_file, create_repository, delete_file, fork_repository, get_commit, get_file_contents, get_label, get_latest_release, get__me, get_release_by_tag, get_tag, get_team_members, get_teams, issue_read, issue_write, list_branches, list_commits, list_issue_fields, list_issue_types, list_issues, list_releases, list_repository_collaborators, list_tags, push_files, search_code, search_commits, search_issues, search_repositories, sub_issue_write, update_issue_comment
```

Running the full agent against a repository issue

* The host passes the target repository and issue number to the agent. The agent loop shows each tool call and its arguments; the MCP server responds with the requested content, and then the agent acts (comment, create issue, etc.).

Example invocation:

```bash theme={null}
python3 run_agent.py --repo $REPO --issue 1
```

Simplified, trimmed trace of the agent's decision and tool usage:

```text theme={null}
Request size before the model does anything: 15,531 tokens (system prompt + request + 32 tool definitions)

---- request ----
Ticket #48213 for Dana Whitfield (dwhitfield) is open as issue #1 in the `btkrausen/brightwater-helpdesk` repository. Please triage it.

---- turn 1 ----
-> issue_read {"method": "get", "owner": "btkrausen", "repo": "brightwater-helpdesk", "issue_number": 1}
<- 1,752 chars back
---- turn 2 ----
-> get_file_contents {"owner": "btkrausen", "repo": "brightwater-helpdesk", "path": "logs/vpn-gw-01/2026-09-21.log"}
<- 10,546 chars back
---- turn 3 ----
-> add_issue_comment {"owner": "btkrausen", "repo": "brightwater-helpdesk", "issue_number": 1, "body": "...triage text..."}
<- 110 chars back
-> issue_write {"method":"create","owner":"btkrausen","repo":"brightwater-helpdesk","title":"Escalation: Endpoint Engineering – Push BWL Endpoint Agent","labels":["escalation","endpoint-engineering"],"body":"...escalation body..."}
<- 86 chars back

Triage posted as a comment on #1, and escalation issue #4 opened for Endpoint Engineering.
```

What the model posted (trimmed example triage comment)

* The agent posted a triage comment and opened an escalation issue. The comment followed the required output structure and included quoted log evidence.

Log evidence collected from the repository file `logs/vpn-gw-01/2026-09-21.log` (example lines found and quoted by the agent):

```text theme={null}
• 03:00:02 POLICY_SYNC policy=Corp-Remote-Std rev=14 result=APPLIED changes="min_agent_version 5.2.0->5.4.0..."
• 08:02:22 POSTURE_CHECK result=FAIL reason=agent_version_below_minimum agent=bwl-ea/5.2.1 required=5.4.0 -> SESSION_REJECT code=0x4C
• 08:05:48 POSTURE_CHECK result=FAIL reason=agent_version_below_minimum agent=bwl-ea/5.2.1 required=5.4.0 -> SESSION_REJECT code=0x4C
• 08:11:17 POSTURE_CHECK result=FAIL reason=agent_version_below_minimum agent=bwl-ea/5.2.1 required=5.4.0 -> SESSION_REJECT code=0x4C
```

Result (example summary produced by the assistant)

```text theme={null}
Summary: Dana's VPN is blocked by posture policy because her BWL Endpoint Agent (5.2.1) is below the required minimum (5.4.0). Password and MFA validated; posture checks failed.

Root cause: Policy update at 03:00:02 raised min_agent_version; POSTURE_CHECK lines show agent_version_below_minimum and SESSION_REJECT code=0x4C.

Fix:
1. Escalate to Endpoint Engineering to push the current BWL Endpoint Agent to BWL-LT-4471.
2. After push, have Dana reboot and reconnect.

Escalate to: Endpoint Engineering (escalation issue #4 opened)
Confidence: High — multiple timestamped posture-check failures matching the policy change.
```

Verify in GitHub

* After the run, refresh the Issues page: the original ticket has a triage comment, and a new escalation issue was created with the required labels and the quoted log evidence.

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/MhECTHF5dIfjn_ai/images/AI-Foundations-for-Technical-Professionals/The-Ecosystem-MCP-Frameworks-and-Automation/Demo-Connecting-an-MCP-Server/github-issue-vpn-connection-rejected.jpg?fit=max&auto=format&n=MhECTHF5dIfjn_ai&q=85&s=cb39b4e6c1caebfe7b9f5d3bbe17c722" alt="A GitHub Issues page showing an open support ticket titled &#x22;VPN: 'Connection rejected by policy (0x4C)'&#x22; with the ticket description and agent notes in the main pane. The right sidebar shows labels, assignee options and other project metadata." width="1920" height="1080" data-path="images/AI-Foundations-for-Technical-Professionals/The-Ecosystem-MCP-Frameworks-and-Automation/Demo-Connecting-an-MCP-Server/github-issue-vpn-connection-rejected.jpg" />
</Frame>

Why this approach is useful

* Reuse the same assistant code and runbook across any MCP server implementing the required toolsets. The host only needs to start and authorize the server and present the model with the tool definitions.
* The model no longer relies on human copy/paste of logs; its output is written directly to the team’s workflow (GitHub issues), so other members see triage instantly.
* Reduces custom integration work: instead of building bespoke clients for each system, the MCP server provides a standard toolset the model can call.

Summary — host / client / server roles

* Host: your script — runs the agent loop and launches the MCP server.
* Client: the small client code inside your host that starts/communicates with the server (stdio or Docker).
* Server: the GitHub MCP server binary (official) that authenticates to GitHub and exposes tools the model can call.

Best practices

* Limit the toolsets you expose to only what’s necessary (`context,repos,issues`).
* Use fine‑grained tokens and store them in environment variables.
* Keep the runbook prescriptive so the agent can act without human intervention.

Links and references

* [GitHub Docs — Personal access tokens](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token)
* [GitHub Documentation](https://docs.github.com/)

If you replicate this pattern, restrict permissions, use fine‑grained tokens, and make sure your runbook clearly defines when to escalate so the agent can act autonomously and safely.

<CardGroup>
  <Card title="Watch Video" icon="video" cta="Learn more" href="https://learn.kodekloud.com/user/courses/ai-foundations-for-technical-professionals/module/dc9aae13-d9f2-42ee-8f39-75abdf313e95/lesson/3d9ab8af-a22a-4378-8377-ba4b42f81b08" />
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.