Skip to content

Mirror: Support refreshing MCP tool, resources, etc lists and avoid prompts (#5410)#27

Merged
jeremylongshore merged 2 commits intomainfrom
mirror/PR-5410
Feb 15, 2026
Merged

Mirror: Support refreshing MCP tool, resources, etc lists and avoid prompts (#5410)#27
jeremylongshore merged 2 commits intomainfrom
mirror/PR-5410

Conversation

@jeremylongshore
Copy link
Copy Markdown
Owner

Mirror of upstream PR #5410

Verdict: APPROVE | Tier 5

Review: kilocode-5410-review.md

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 15, 2026

Warning

Rate limit exceeded

@jeremylongshore has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 29 minutes and 28 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch mirror/PR-5410

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello @jeremylongshore, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the Model Context Protocol (MCP) integration by enabling automatic updates of tool, resource, and prompt lists. This ensures that the development environment remains synchronized with server-side changes without requiring manual refreshes, thereby improving responsiveness and user experience. Additionally, the handling of unaddressed server notifications has been refined to prevent disruptive user prompts, opting instead for silent logging to maintain a smoother workflow.

Highlights

  • Automatic List Refreshing: Implemented automatic refreshing of MCP tool, resource, and prompt lists whenever the connected server notifies of changes, eliminating the need for manual intervention.
  • Improved Notification Handling: Modified the NotificationService to accept a callback for refreshing capabilities and changed the default behavior for unhandled notifications to log them silently instead of displaying intrusive user prompts.
  • Comprehensive Testing: Added extensive unit tests for the NotificationService to ensure the new notification handling logic functions correctly and reliably.
  • Internal Tooling Files: Introduced several new .beads configuration and state files, which appear to be related to internal daemon management and versioning, though their specific context within this PR is not explicitly detailed.
Changelog
  • .beads/.local_version
    • Added a file containing the local version string.
  • .beads/beads.left.meta.json
    • Added a JSON metadata file including version, timestamp, and commit information.
  • .beads/daemon.lock
    • Added a JSON file containing daemon process details such as PID, parent PID, database path, version, and start time.
  • .beads/daemon.pid
    • Added a file storing the daemon's process ID.
  • .beads/last-touched
    • Added a file containing a string identifier.
  • .beads/metadata.json
    • Added a JSON file specifying database and JSONL export names.
  • .beads/sync-state.json
    • Added a JSON file detailing synchronization state, including failure information and backoff parameters.
  • src/services/mcp/McpHub.ts
    • Passed a new onRefreshCapabilities callback to the kiloNotificationService.connect method to handle list change notifications.
  • src/services/mcp/kilocode/NotificationService.ts
    • Extended the connect method to accept an optional onRefreshCapabilities callback.
    • Added new notification handlers for ResourceListChangedNotificationSchema, ToolListChangedNotificationSchema, and PromptListChangedNotificationSchema to invoke the refresh callback.
    • Updated the fallbackNotificationHandler to log unhandled notifications to the console instead of displaying VS Code information messages.
    • Imported new notification schemas from @modelcontextprotocol/sdk/types.js.
    • Defined the RefreshCapabilitiesCallback type.
  • src/services/mcp/kilocode/tests/NotificationService.spec.ts
    • Added a new test file to cover the functionality of NotificationService, including logging messages, resource/tool/prompt list changes, and fallback notification handling.
Ignored Files
  • Ignored by pattern: .github/workflows/** (1)
    • .github/workflows/auto-triage.yml
Activity
  • The pull request has been reviewed and approved.
  • A detailed review markdown file (kilocode-5410-review.md) is available for reference.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Support refreshing MCP tool, resources, and prompts lists with automatic capability refresh

✨ Enhancement 🧪 Tests

Grey Divider

Walkthroughs

Description
• Add support for refreshing MCP server capabilities when tools, resources, or prompts change
• Handle ResourceListChanged, ToolListChanged, and PromptListChanged notifications
• Implement RefreshCapabilitiesCallback to automatically refresh server state
• Change fallback notification handler to log silently instead of showing user prompts
• Add comprehensive test suite for NotificationService with 346 lines of test coverage
• Add GitHub Actions auto-triage workflow for automatic issue and PR labeling
Diagram
flowchart LR
  MCP["MCP Server Notifications"]
  NS["NotificationService"]
  RC["RefreshCapabilitiesCallback"]
  HUB["McpHub"]
  
  MCP -->|ResourceListChanged| NS
  MCP -->|ToolListChanged| NS
  MCP -->|PromptListChanged| NS
  NS -->|Invoke Callback| RC
  RC -->|fetchAvailableServerCapabilities| HUB
  RC -->|notifyWebviewOfServerChanges| HUB
Loading

Grey Divider

File Changes

1. src/services/mcp/kilocode/NotificationService.ts ✨ Enhancement +56/-4

Add capability refresh handlers for list change notifications

src/services/mcp/kilocode/NotificationService.ts


2. src/services/mcp/kilocode/__tests__/NotificationService.spec.ts 🧪 Tests +346/-0

Add comprehensive test suite for NotificationService

src/services/mcp/kilocode/tests/NotificationService.spec.ts


3. src/services/mcp/McpHub.ts ✨ Enhancement +6/-1

Pass refresh callback to notification service connect method

src/services/mcp/McpHub.ts


View more (10)
4. .github/workflows/auto-triage.yml ⚙️ Configuration changes +126/-0

Add GitHub Actions workflow for automatic issue and PR triaging

.github/workflows/auto-triage.yml


5. .beads/beads.db-shm Miscellaneous +0/-0

Database shared memory file update

.beads/beads.db-shm


6. .beads/sync-state.json Miscellaneous +7/-0

Sync state metadata for beads tool

.beads/sync-state.json


7. .beads/beads.left.meta.json Miscellaneous +1/-0

Beads tool version and metadata

.beads/beads.left.meta.json


8. .beads/metadata.json Miscellaneous +4/-0

Beads database configuration metadata

.beads/metadata.json


9. .beads/.local_version Miscellaneous +1/-0

Local beads tool version file

.beads/.local_version


10. .beads/last-touched Miscellaneous +1/-0

Last touched metadata for beads tool

.beads/last-touched


11. .beads/daemon.pid Miscellaneous +1/-0

Daemon process ID file

.beads/daemon.pid


12. .beads/beads.db-wal Additional files +0/-0

...

.beads/beads.db-wal


13. .beads/beads.left.jsonl Additional files +0/-0

...

.beads/beads.left.jsonl


Grey Divider

Qodo Logo

@github-actions
Copy link
Copy Markdown

Failed to generate code suggestions for PR

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for refreshing MCP tool, resource, and prompt lists when the server sends a notification about changes. This is achieved by adding new notification handlers in NotificationService and passing a refresh callback from McpHub. The changes are well-implemented and include comprehensive unit tests for the new functionality in NotificationService. I have one suggestion to reduce code duplication in the new notification handlers.

Comment on lines +55 to +83
// Handle resource list changes - refresh capabilities silently
client.setNotificationHandler(ResourceListChangedNotificationSchema, async () => {
console.log(`MCP ${name}: resources list changed, refreshing capabilities`)
try {
await onRefreshCapabilities?.(name)
} catch (error) {
console.error(`MCP ${name}: failed to refresh capabilities after resource list change:`, error)
}
})

// Handle tool list changes - refresh capabilities silently
client.setNotificationHandler(ToolListChangedNotificationSchema, async () => {
console.log(`MCP ${name}: tools list changed, refreshing capabilities`)
try {
await onRefreshCapabilities?.(name)
} catch (error) {
console.error(`MCP ${name}: failed to refresh capabilities after tool list change:`, error)
}
})

// Handle prompt list changes - refresh capabilities silently
client.setNotificationHandler(PromptListChangedNotificationSchema, async () => {
console.log(`MCP ${name}: prompts list changed, refreshing capabilities`)
try {
await onRefreshCapabilities?.(name)
} catch (error) {
console.error(`MCP ${name}: failed to refresh capabilities after prompt list change:`, error)
}
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The notification handlers for resource, tool, and prompt list changes contain duplicated logic. To improve maintainability and reduce redundancy, you can extract this logic into a helper function.

		const createRefreshHandler = (listType: string) => async () => {
			console.log(`MCP ${name}: ${listType} list changed, refreshing capabilities`);
			try {
				await onRefreshCapabilities?.(name);
			} catch (error) {
				console.error(`MCP ${name}: failed to refresh capabilities after ${listType} list change:`, error);
			}
		};

		// Handle resource list changes - refresh capabilities silently
		client.setNotificationHandler(ResourceListChangedNotificationSchema, createRefreshHandler("resources"));

		// Handle tool list changes - refresh capabilities silently
		client.setNotificationHandler(ToolListChangedNotificationSchema, createRefreshHandler("tools"));

		// Handle prompt list changes - refresh capabilities silently
		client.setNotificationHandler(PromptListChangedNotificationSchema, createRefreshHandler("prompts"));

@jeremylongshore jeremylongshore merged commit 7d3ab1b into main Feb 15, 2026
11 of 15 checks passed
@qodo-code-review
Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (1) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Logs raw notification object 📘 Rule violation ⛨ Security
Description
New handlers log full MCP notifications and error objects via console.log/console.error, which
can include sensitive data in params and are not structured for auditing. This increases the risk
of leaking secrets/PII into logs and makes log monitoring/parsing harder.
Code

src/services/mcp/kilocode/NotificationService.ts[R55-89]

+		// Handle resource list changes - refresh capabilities silently
+		client.setNotificationHandler(ResourceListChangedNotificationSchema, async () => {
+			console.log(`MCP ${name}: resources list changed, refreshing capabilities`)
+			try {
+				await onRefreshCapabilities?.(name)
+			} catch (error) {
+				console.error(`MCP ${name}: failed to refresh capabilities after resource list change:`, error)
+			}
+		})
+
+		// Handle tool list changes - refresh capabilities silently
+		client.setNotificationHandler(ToolListChangedNotificationSchema, async () => {
+			console.log(`MCP ${name}: tools list changed, refreshing capabilities`)
+			try {
+				await onRefreshCapabilities?.(name)
+			} catch (error) {
+				console.error(`MCP ${name}: failed to refresh capabilities after tool list change:`, error)
+			}
+		})
+
+		// Handle prompt list changes - refresh capabilities silently
+		client.setNotificationHandler(PromptListChangedNotificationSchema, async () => {
+			console.log(`MCP ${name}: prompts list changed, refreshing capabilities`)
+			try {
+				await onRefreshCapabilities?.(name)
+			} catch (error) {
+				console.error(`MCP ${name}: failed to refresh capabilities after prompt list change:`, error)
+			}
+		})
+
+		// Fallback for any other unhandled notifications - log silently, don't notify user
+		// This prevents raw JSON-RPC messages from being displayed as VS Code notifications
		client.fallbackNotificationHandler = async (notification) => {
-			vscode.window.showInformationMessage(`MCP ${name}: ${JSON.stringify(notification)}`)
+			console.log(`MCP ${name}: unhandled notification`, notification)
		}
Evidence
PR Compliance ID 5 requires structured logs and forbids sensitive data in logs. The new code logs
entire notification payloads (including params) and logs raw error objects, which may contain
sensitive details and stack traces.

Rule 5: Generic: Secure Logging Practices
src/services/mcp/kilocode/NotificationService.ts[55-83]
src/services/mcp/kilocode/NotificationService.ts[85-89]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`NotificationService` logs raw MCP notification payloads (including full `notification` objects) and raw `error` objects using `console.log`/`console.error`. This can leak sensitive data from notification `params` and produces unstructured logs.

## Issue Context
MCP servers can send arbitrary notification `params` (potentially containing secrets, file contents, or other sensitive values). Logging full payloads and raw errors violates the secure logging requirement.

## Fix Focus Areas
- src/services/mcp/kilocode/NotificationService.ts[55-89]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Workflow shell injection 🐞 Bug ⛨ Security
Description
Untrusted issue/PR content is interpolated into a double-quoted bash string passed to `kilocode
--auto; ITEM_TITLE` is unsanitized and can contain backticks/$() to achieve command execution.
Because this workflow also exports an integration token, successful injection could exfiltrate
secrets or modify repo state via GitHub CLI.
Code

.github/workflows/auto-triage.yml[R47-67]

+          ITEM_NUMBER: ${{ github.event_name == 'issues' && github.event.issue.number || github.event.pull_request.number }}
+          ITEM_TITLE: ${{ github.event_name == 'issues' && github.event.issue.title || github.event.pull_request.title }}
+          ITEM_BODY: ${{ github.event_name == 'issues' && github.event.issue.body || github.event.pull_request.body }}
+        run: |
+          # Sanitize body - remove shell metacharacters
+          SAFE_BODY=$(echo "$ITEM_BODY" | head -c 2000 | tr -d '`$(){}[]|;&<>\\' | tr '\n' ' ')
+          
+          # Determine gh command based on event type
+          if [ "$EVENT_TYPE" = "issues" ]; then
+            GH_CMD="gh issue edit"
+            ITEM_TYPE="issue"
+          else
+            GH_CMD="gh pr edit"
+            ITEM_TYPE="pull request"
+          fi
+          
+          kilocode --auto "Triage this GitHub ${ITEM_TYPE}:
+
+          Number: ${ITEM_NUMBER}
+          Title: ${ITEM_TITLE}
+          Body: ${SAFE_BODY}
Evidence
The workflow constructs a prompt in a double-quoted string and inserts ${ITEM_TITLE} without
sanitization. Backticks and $() inside double quotes are evaluated by bash, enabling RCE. The
workflow also exports KILOCODE_TOKEN from secrets in the same step, increasing impact.

.github/workflows/auto-triage.yml[34-39]
.github/workflows/auto-triage.yml[47-67]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The auto-triage workflow is vulnerable to shell injection because it embeds `${ITEM_TITLE}` (untrusted) into a double-quoted bash string passed to `kilocode --auto`.

### Issue Context
Any user can open an issue with a malicious title containing backticks or `$()`; bash will evaluate these inside the double-quoted string. The step also exports `KILOCODE_TOKEN`.

### Fix Focus Areas
- .github/workflows/auto-triage.yml[47-67]
- .github/workflows/auto-triage.yml[34-39]

### Suggested direction
- Sanitize `ITEM_TITLE` similarly to `ITEM_BODY`, and also remove `&quot;` from both.
- Prefer generating the prompt without shell interpolation (scripted construction/escaping or file-based input) so untrusted text never gets evaluated by bash.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Accidental .beads commit 🐞 Bug ⛯ Reliability
Description
The PR commits .beads/ local runtime/state files (pid, timestamps, sync failures) and a SQLite shm
artifact; these will churn, bloat the repo, and cause merge conflicts. They should be removed from
the PR and added to the root .gitignore.
Code

.beads/sync-state.json[R1-7]

+{
+  "last_failure": "2026-02-14T20:42:41.363720889-06:00",
+  "failure_count": 7,
+  "backoff_until": "2026-02-14T21:12:41.36372132-06:00",
+  "needs_manual_sync": true,
+  "failure_reason": "git pull failed: exit status 1\nfatal: couldn't find remote ref review/PR-5667\n"
+}
Evidence
.beads contains clearly machine-local state (pid file, timestamps, failure backoff) and is not
ignored at the repo root, so it will keep being committed/changed. Another workspace in the repo
already ignores .beads/, reinforcing that it’s local state.

.beads/sync-state.json[1-7]
.beads/daemon.pid[1-1]
.gitignore[35-79]
apps/kilocode-docs/.gitignore[1-10]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`.beads/` appears to be local runtime/database state and should not be tracked.

### Issue Context
These files include process IDs and sync timestamps/errors and will change frequently.

### Fix Focus Areas
- .beads/sync-state.json[1-7]
- .beads/daemon.pid[1-1]
- .gitignore[35-79]

### Suggested direction
- Remove `.beads/` directory contents from version control.
- Add `.beads/` to root `.gitignore` (optionally also ignore SQLite shm/wal patterns).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

4. Untrusted triage token usage 🐞 Bug ⛯ Reliability
Description
The workflow triggers on every newly opened issue/PR (excluding only bots) and uses an integration
token to call an LLM. This allows external users to drive recurring API usage/cost and increases
operational risk even if command injection is fixed.
Code

.github/workflows/auto-triage.yml[R3-39]

+on:
+  issues:
+    types: [opened]
+  pull_request:
+    types: [opened]
+
+jobs:
+  triage:
+    runs-on: ubuntu-latest
+    # Skip bot-created issues/PRs
+    if: |
+      (github.event_name == 'issues' && github.event.issue.user.type != 'Bot') ||
+      (github.event_name == 'pull_request' && github.event.pull_request.user.type != 'Bot')
+    permissions:
+      contents: read
+      issues: write
+      pull-requests: write
+
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v4
+
+      - name: Setup Node.js
+        uses: actions/setup-node@v4
+        with:
+          node-version: "20"
+
+      - name: Install Kilo Code CLI
+        run: npm install -g @kilocode/cli
+
+      - name: Triage
+        env:
+          KILO_PROVIDER_TYPE: kilocode
+          KILOCODE_TOKEN: ${{ secrets.KILOCODE_INTEGRATION_TOKEN }}
+          KILOCODE_ORGANIZATION_ID: ${{ secrets.KILOCODE_INTEGRATION_ORGANIZATION_ID }}
+          KILOCODE_MODEL: claude-haiku-4-5
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Evidence
The workflow runs on issues: opened and pull_request: opened for non-bot users, and it exports
an integration secret token for the triage step. That combination permits any external user to
trigger the action and consume resources.

.github/workflows/auto-triage.yml[3-7]
.github/workflows/auto-triage.yml[12-15]
.github/workflows/auto-triage.yml[34-37]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Auto-triage runs for any newly opened issue/PR by any non-bot user while using an integration token, enabling cost/abuse.

### Issue Context
The workflow is triggered on public user actions and calls `kilocode` with integration secrets.

### Fix Focus Areas
- .github/workflows/auto-triage.yml[3-15]
- .github/workflows/auto-triage.yml[34-39]

### Suggested direction
- Gate execution by `github.event.issue.author_association` / `github.event.pull_request.author_association`.
- Add `concurrency:` to limit parallel runs.
- Optionally skip/label-only without LLM for untrusted associations.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment on lines +55 to 89
// Handle resource list changes - refresh capabilities silently
client.setNotificationHandler(ResourceListChangedNotificationSchema, async () => {
console.log(`MCP ${name}: resources list changed, refreshing capabilities`)
try {
await onRefreshCapabilities?.(name)
} catch (error) {
console.error(`MCP ${name}: failed to refresh capabilities after resource list change:`, error)
}
})

// Handle tool list changes - refresh capabilities silently
client.setNotificationHandler(ToolListChangedNotificationSchema, async () => {
console.log(`MCP ${name}: tools list changed, refreshing capabilities`)
try {
await onRefreshCapabilities?.(name)
} catch (error) {
console.error(`MCP ${name}: failed to refresh capabilities after tool list change:`, error)
}
})

// Handle prompt list changes - refresh capabilities silently
client.setNotificationHandler(PromptListChangedNotificationSchema, async () => {
console.log(`MCP ${name}: prompts list changed, refreshing capabilities`)
try {
await onRefreshCapabilities?.(name)
} catch (error) {
console.error(`MCP ${name}: failed to refresh capabilities after prompt list change:`, error)
}
})

// Fallback for any other unhandled notifications - log silently, don't notify user
// This prevents raw JSON-RPC messages from being displayed as VS Code notifications
client.fallbackNotificationHandler = async (notification) => {
vscode.window.showInformationMessage(`MCP ${name}: ${JSON.stringify(notification)}`)
console.log(`MCP ${name}: unhandled notification`, notification)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Logs raw notification object 📘 Rule violation ⛨ Security

New handlers log full MCP notifications and error objects via console.log/console.error, which
can include sensitive data in params and are not structured for auditing. This increases the risk
of leaking secrets/PII into logs and makes log monitoring/parsing harder.
Agent Prompt
## Issue description
`NotificationService` logs raw MCP notification payloads (including full `notification` objects) and raw `error` objects using `console.log`/`console.error`. This can leak sensitive data from notification `params` and produces unstructured logs.

## Issue Context
MCP servers can send arbitrary notification `params` (potentially containing secrets, file contents, or other sensitive values). Logging full payloads and raw errors violates the secure logging requirement.

## Fix Focus Areas
- src/services/mcp/kilocode/NotificationService.ts[55-89]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +47 to +67
ITEM_NUMBER: ${{ github.event_name == 'issues' && github.event.issue.number || github.event.pull_request.number }}
ITEM_TITLE: ${{ github.event_name == 'issues' && github.event.issue.title || github.event.pull_request.title }}
ITEM_BODY: ${{ github.event_name == 'issues' && github.event.issue.body || github.event.pull_request.body }}
run: |
# Sanitize body - remove shell metacharacters
SAFE_BODY=$(echo "$ITEM_BODY" | head -c 2000 | tr -d '`$(){}[]|;&<>\\' | tr '\n' ' ')

# Determine gh command based on event type
if [ "$EVENT_TYPE" = "issues" ]; then
GH_CMD="gh issue edit"
ITEM_TYPE="issue"
else
GH_CMD="gh pr edit"
ITEM_TYPE="pull request"
fi

kilocode --auto "Triage this GitHub ${ITEM_TYPE}:

Number: ${ITEM_NUMBER}
Title: ${ITEM_TITLE}
Body: ${SAFE_BODY}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Workflow shell injection 🐞 Bug ⛨ Security

Untrusted issue/PR content is interpolated into a double-quoted bash string passed to `kilocode
--auto; ITEM_TITLE` is unsanitized and can contain backticks/$() to achieve command execution.
Because this workflow also exports an integration token, successful injection could exfiltrate
secrets or modify repo state via GitHub CLI.
Agent Prompt
### Issue description
The auto-triage workflow is vulnerable to shell injection because it embeds `${ITEM_TITLE}` (untrusted) into a double-quoted bash string passed to `kilocode --auto`.

### Issue Context
Any user can open an issue with a malicious title containing backticks or `$()`; bash will evaluate these inside the double-quoted string. The step also exports `KILOCODE_TOKEN`.

### Fix Focus Areas
- .github/workflows/auto-triage.yml[47-67]
- .github/workflows/auto-triage.yml[34-39]

### Suggested direction
- Sanitize `ITEM_TITLE` similarly to `ITEM_BODY`, and also remove `"` from both.
- Prefer generating the prompt without shell interpolation (scripted construction/escaping or file-based input) so untrusted text never gets evaluated by bash.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread .beads/sync-state.json
Comment on lines +1 to +7
{
"last_failure": "2026-02-14T20:42:41.363720889-06:00",
"failure_count": 7,
"backoff_until": "2026-02-14T21:12:41.36372132-06:00",
"needs_manual_sync": true,
"failure_reason": "git pull failed: exit status 1\nfatal: couldn't find remote ref review/PR-5667\n"
} No newline at end of file
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. Accidental .beads commit 🐞 Bug ⛯ Reliability

The PR commits .beads/ local runtime/state files (pid, timestamps, sync failures) and a SQLite shm
artifact; these will churn, bloat the repo, and cause merge conflicts. They should be removed from
the PR and added to the root .gitignore.
Agent Prompt
### Issue description
`.beads/` appears to be local runtime/database state and should not be tracked.

### Issue Context
These files include process IDs and sync timestamps/errors and will change frequently.

### Fix Focus Areas
- .beads/sync-state.json[1-7]
- .beads/daemon.pid[1-1]
- .gitignore[35-79]

### Suggested direction
- Remove `.beads/` directory contents from version control.
- Add `.beads/` to root `.gitignore` (optionally also ignore SQLite shm/wal patterns).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@jeremylongshore jeremylongshore deleted the mirror/PR-5410 branch February 15, 2026 03:12
@jeremylongshore
Copy link
Copy Markdown
Owner Author

Review: kilocode Kilo-Org#5410

Support refreshing MCP tool, resources, etc lists and avoid prompts by @lambertjosh

Methodology

Checklist

Check Result Notes
Correctness PASS Correctly handles all three MCP list_changed notifications per spec
Conventions PASS kilocode_change markers present in McpHub.ts
Changeset FAIL Missing changeset (changeset-bot flagged)
Tests PASS 346 lines of comprehensive tests covering all notification types
i18n N/A No user-facing strings
Types PASS Proper TypeScript types, exported callback type
Security PASS No security concerns
Scope PASS Focused: 3 files, single purpose

Findings

YELLOW - Missing changeset

Changeset-bot flagged this PR. A patch changeset for kilo-code should be added describing the MCP notification handling improvement.

YELLOW - Potential race condition in rapid notifications

If an MCP server sends tools/list_changed, resources/list_changed, and prompts/list_changed in quick succession, three concurrent calls to fetchAvailableServerCapabilities + notifyWebviewOfServerChanges will execute. The handlers do not debounce or serialize. If fetchAvailableServerCapabilities is not reentrant, this could cause inconsistent state.

// Each handler independently calls the callback:
client.setNotificationHandler(ToolListChangedNotificationSchema, async () => {
    await onRefreshCapabilities?.(name)  // Could overlap with resource/prompt handlers
})

Consider debouncing the refresh callback or queuing notifications to batch refresh all capabilities once.

GRAY - Fallback handler silently logs instead of notifying

The previous behavior was vscode.window.showInformationMessage(...) for unhandled notifications, which was noisy (the original problem). The new behavior is console.log(...). This is the correct fix -- unhandled MCP notifications should not create VS Code toasts. The change correctly addresses the issue shown in the PR screenshot.

GRAY - Removed kilocode_change comment in NotificationService

Line 15 in the original NotificationService.ts had a // kilocode_change comment on the data fallback line. In the PR diff, this comment is removed. Since this is in the src/services/mcp/kilocode/ directory (a kilocode-specific path), the marker is not strictly required, so this is acceptable.

GRAY - Error handling pattern is consistent

Each notification handler catches and logs errors from the refresh callback, preventing a single failed refresh from breaking the notification handler chain. This is the correct pattern:

try {
    await onRefreshCapabilities?.(name)
} catch (error) {
    console.error(`MCP ${name}: failed to refresh capabilities after tool list change:`, error)
}

GRAY - Test coverage is thorough

346 lines of tests covering:

  • All 4 notification handler registrations
  • Fallback handler assignment
  • All logging levels (info, warning, alert, error, critical, emergency)
  • Logger prefix behavior
  • Refresh callback invocation for all 3 list_changed types
  • Error handling when callback fails
  • No-callback behavior (optional parameter)
  • No user notification for list changes
  • Fallback handler logging without toasts

CI Status

Check Result
compile PASS
test-extension (ubuntu) PASS
test-extension (windows) PASS
test-jetbrains PASS
test-webview (ubuntu) PASS
test-webview (windows) PASS
test-cli PASS
build-cli PASS
check-translations PASS
Build Docusaurus Site PASS

All CI checks pass.

Code Snippets

McpHub callback wiring:

// src/services/mcp/McpHub.ts
this.kiloNotificationService.connect(name, connection.client, async (serverName) => {
    await this.fetchAvailableServerCapabilities(serverName, source)
    await this.notifyWebviewOfServerChanges()
})

NotificationService type:

// src/services/mcp/kilocode/NotificationService.ts
export type RefreshCapabilitiesCallback = (serverName: string) => Promise<void>

Verdict

APPROVE -- This is a clean, well-tested fix for an annoying user experience problem (raw JSON-RPC notifications appearing as VS Code toasts). The implementation correctly follows the MCP specification for tools/list_changed, resources/list_changed, and prompts/list_changed notifications. The test coverage is exemplary at 346 lines for 62 lines of production code.

Minor items to address before merge:

  1. Add a changeset (patch for kilo-code)
  2. Consider debouncing rapid successive notifications (nice-to-have, not blocking)

The author acknowledges this was "vibe coded" in the description, but the result is well-structured and the test suite is comprehensive enough to validate the behavior.

@jeremylongshore
Copy link
Copy Markdown
Owner Author

Review Journal: kilocode Kilo-Org#5410

PR: #5410 |
Title: Support refreshing MCP tool, resources, etc lists and avoid prompts |
Author: @lambertjosh |
Category: feature | Tier: 5 | Size: 413 lines, 3 files


Summary

Fixes annoying MCP tool change notification toasts by properly handling list_changed notifications from MCP servers. Instead of showing raw JSON-RPC as VS Code information messages, the extension now silently refreshes its cached capabilities and logs to console. Includes 346 lines of thorough tests.

First Impressions

The PR screenshot showing 7+ notification popups makes the problem immediately clear. Author (lambertjosh / Joshua Lambert) explicitly notes "vibe coded, tested but not reviewed at a code level, in draft." Despite this disclaimer, the code is well-organized.

What I Looked At

  • Full diff: 408+/5- across 3 files
  • NotificationService.ts on main branch (39 lines -- the complete service)
  • McpHub.ts context around the kiloNotificationService.connect() call
  • New test file: NotificationService.spec.ts (346 lines)
  • MCP SDK types for notification schemas
  • PR comments and CI status

Analysis

Notification Routing

The original code had a fallbackNotificationHandler that called vscode.window.showInformationMessage() with the raw JSON. This fired on every list_changed notification, which happens frequently during initialization and provider changes. The fix:

  1. Registers explicit handlers for ResourceListChangedNotificationSchema, ToolListChangedNotificationSchema, PromptListChangedNotificationSchema
  2. Each handler calls the new RefreshCapabilitiesCallback to re-fetch server capabilities
  3. The fallback handler now just console.log()s unknown notifications

This follows the MCP specification correctly. The notification schemas are imported from @modelcontextprotocol/sdk/types.js, ensuring type safety.

Callback Architecture

The RefreshCapabilitiesCallback is passed from McpHub into NotificationService.connect(). This maintains the separation of concerns -- NotificationService handles notifications but delegates the actual refresh to the caller. The callback is optional (onRefreshCapabilities?: RefreshCapabilitiesCallback), preserving backward compatibility.

Race Condition (Minor)

Three notifications arriving in quick succession will trigger three concurrent refreshes. In practice, fetchAvailableServerCapabilities likely involves MCP SDK calls that are serialized per server. But the notifyWebviewOfServerChanges() could fire multiple times with intermediate states. This is a minor issue -- the final state will be correct, just potentially flickery.

Verification

  • CI: All 11 checks pass
  • Tests: 346 lines covering all paths (verified by reading test file)
  • Changeset: Missing (changeset-bot flagged)
  • Draft status: PR description says "in draft" but it appears to be a regular PR

Lessons Learned

  1. "Vibe coded" can still produce clean code if the problem domain is well-understood.
  2. MCP notification handling is a common pain point -- this fix should be a standard part of any MCP hub implementation.
  3. Test-to-production ratio of ~5.6:1 (346 test lines / 62 production lines) is excellent for a notification service.

Review methodology: AI PR Review Case Studies | Reviewed with GWI + Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant