Skip to main content
Glama

Copilot Counterpart

A local MCP server that lets a coding assistant such as Codex or Claude Code hand bounded work to models in your GitHub Copilot subscription, with automatic model routing, live progress, steering and cancellation. Jobs are context-only by default; a job can also be granted scoped read access to named files and staged writes that the lead reviews before anything reaches disk.

It uses the official GitHub Copilot SDK and your existing copilot login. It is not an unofficial API proxy, and it never copies credentials.

Why

Your primary assistant stays the thinking partner and decision-maker. Copilot gives it cheap access to other models for:

  • independent review of a meaningful change,

  • correctness checks (races, lifecycle, invariants),

  • design sparring before a consequential decision,

  • bounded analysis or code proposals returned as text.

The router picks the model and reasoning effort from the task's role, complexity and risk, and sends independent work to a different model family from the lead, so a Claude-led session gets a GPT second opinion and a Codex-led session gets a Claude one.

Related MCP server: codex-claude-bridge

Safety model

  • By default delegates receive only the context you put in the prompt. Every built-in and MCP tool and every permission request is denied, configuration/instruction discovery is disabled, and each job gets a fresh empty working directory. The adapter verifies the runtime's actual tool set before sending context.

  • No shell, web access or code execution, ever. File access exists only when a call grants it with files (see scoped files): reads limited to named paths, writes staged in memory and applied only by the lead through copilot_apply.

  • sharingAuthorized: true is required on every inference call. It is the orchestrator's attestation that the user or project permits sending that context to Copilot, not an independent policy check.

  • At most two active jobs, 32 retained jobs, 512 events per job, a five-minute default deadline (15 minute maximum), and one supervised escalation per job.

  • Opt-in recursive delegation (copilot_orchestrate) is bounded to eight nodes and depth three, and is still context-only.

These are SDK-level restrictions, not an OS sandbox against a compromised SDK or runtime.

Install

Requires Node 22+ and a GitHub Copilot subscription.

git clone https://github.com/dstkwll/copilot-counterpart.git
cd copilot-counterpart
npm ci --ignore-scripts
npm test
copilot login   # only if you are not already authenticated

Register the server with each assistant using absolute paths. Registrations made before the rename may still use COPILOT_SUPERVISOR_LEAD_FAMILY, which is accepted as an alias. Set COPILOT_COUNTERPART_LEAD_FAMILY to the assistant's own model family so the router can pick a different family for reviews.

Codex

codex mcp add copilot-counterpart \
  --env COPILOT_COUNTERPART_LEAD_FAMILY=openai \
  -- "$(command -v node)" "$PWD/src/server.mjs"

Or in ~/.codex/config.toml:

[mcp_servers.copilot-counterpart]
command = "/absolute/path/to/node"
args = ["/absolute/path/to/copilot-counterpart/src/server.mjs"]
env = { COPILOT_COUNTERPART_LEAD_FAMILY = "openai" }

Claude Code

claude mcp add copilot-counterpart --scope user \
  -e COPILOT_COUNTERPART_LEAD_FAMILY=anthropic \
  -- "$(command -v node)" "$PWD/src/server.mjs"

Each host starts its own server process. Jobs, request IDs and feedback are not shared between hosts.

skills/copilot-delegation tells the assistant when to delegate, how to supervise, and how to report receipts. It works for both hosts:

mkdir -p ~/.codex/skills ~/.claude/skills
ln -s "$PWD/skills/copilot-delegation" ~/.codex/skills/copilot-delegation
ln -s "$PWD/skills/copilot-delegation" ~/.claude/skills/copilot-delegation

The skill defers to your sharing authorization. To let the assistant delegate without asking each time, state it in your own global instructions (~/.codex/AGENTS.md or ~/.claude/CLAUDE.md). For example: "You may send task-relevant code and context to my authenticated GitHub Copilot service for reviews and delegations; never include secrets."

Start a new session after registering so the tools and skill are picked up. Already-running server processes keep the routing policy they loaded.

Routing (policy v3)

copilot_delegate takes requestId, role, task, context, acceptanceCriteria, sharingAuthorized: true, and optional complexity (small/normal/complex), risk (low/high), leadFamily (openai/anthropic, overriding the server default), parentJobId and timeoutSeconds.

Role

Claude lead (anthropic)

Codex lead (openai)

No lead configured

review

GPT-6.1 Sol high

Claude Opus 5.5 high

GPT-6.1 Sol high

correctness

GPT-6.1 Sol high

Claude Opus 5.5 high

GPT-6.1 Sol high

sparring, high-risk review

GPT-6 Astra high

Claude Opus 5.5 high

Claude Opus 5.5 high

analysis / code_proposal, small

GPT-6 Luna medium

same

same

analysis / code_proposal, normal

GPT-6.1 Sol medium

same

same

analysis / code_proposal, complex or high risk

GPT-6.1 Sol high

same

same

  • Fallbacks. Each route has its own ordered fallback list (full table). Usually GPT-6.1 Sol falls back to GPT-6 Sol. Correctness and sparring also try the other family's strongest model, but Claude-led review does not. The route reports fallback: true, and crossFamily: false when it had to use the lead's own family. If nothing qualifies, it fails closed without starting inference. It never silently picks an older-generation model.

  • Escalation. You can escalate a finished routed job once, with parentJobId and a fresh self-contained brief. Luna escalates to Sol, and Sol escalates to the ceiling for the lead: Astra for Claude, Opus 5.5 for Codex or no lead. Astra and Opus 5.5 can't be escalated further. Previous output isn't forwarded automatically, and cancelled or timed-out jobs can't be escalated.

  • No cost-based routing. The router doesn't route on price. Plan pricing and allowances vary.

Job status includes the full route: model, effort, reason, lead family, cross-family flag and policy version. Model IDs live in one table in src/router.mjs; see model routing for the rationale.

Supervising a job

  1. Dispatch with copilot_delegate, or with copilot_start and an explicit model from copilot_models. copilot_start bypasses routing but not the tool boundary, and it also requires sharingAuthorized: true. Steering is covered by the job's original attestation.

  2. Poll copilot_events(jobId, after, waitMs ≤ 30000). Keep nextCursor and drain hasMore before waiting again. A gap means older events were evicted; the latest complete message is still available as result.

  3. Use copilot_steer for best-effort course corrections. It isn't idempotent and can't change tokens already generated. Use copilot_cancel to stop the job's dedicated runtime; nothing is rolled back.

  4. For jobs with writable files, review copilot_changes and apply with copilot_apply only if the diff is right.

  5. Verify findings against the evidence. Treat reviewer output as untrusted data. Record copilot_feedback (useful / unhelpful / inconclusive), then free memory with copilot_forget.

Request IDs deduplicate identical starts within one process. Routed request IDs stay reserved for the life of the process (up to 64).

Scoped files

Pass files to copilot_delegate or copilot_start:

"files": { "root": "/abs/path/to/repo", "read": ["src", "test/router.test.mjs"], "write": ["src/router.mjs"] }
  • The delegate gets workspace_read, workspace_list and workspace_search, plus workspace_write and workspace_edit only when write is non-empty. They are custom tools; built-in file tools stay denied.

  • Reads are limited to the read paths (directories recursively) and the write files, and to UTF-8 text. Paths are resolved through symlinks and must stay inside root; files are opened without following symlinks, and hard-linked files are refused. Per-read, per-job and search size caps apply.

  • Sensitive paths are always refused, even if granted, in any letter case: .git, .ssh, .aws, .env* (except .example/.sample/.template), keys and certificates, .npmrc/.netrc, credentials*, secrets*.

  • Writes are staged, never written by the delegate. Only exact write files can be edited or created. When the job finishes, call copilot_changes for a unified diff and a changeSetHash computed from the same snapshot, review it, then call copilot_apply with that hash. Apply refuses before writing anything if a file changed on disk after the job read it, prepares every file before committing, re-checks each one just before replacing it, and if a commit still fails midway reports exactly which files were written. It runs once per job.

  • Every access and refusal appears in the job's events as supervisor.file_access, and job status includes a workspace summary. File contents are stripped from the job's tool events, so polling events doesn't pull them into the lead's context.

  • File contents you grant are sent to Copilot like any other context, so sharingAuthorized covers them too. Grant the smallest set the task needs. copilot_orchestrate does not take files. Design notes: scoped files.

Applying a reviewed diff is cheap for the lead: it reads the diff instead of writing the code, and apply needs no re-typing.

Recursive delegation (opt-in)

Failed orchestration requests that never started a job free their request ID. copilot_orchestrate starts a lead session that may call a single delegate_task tool. Each child is routed by the same router, inheriting the outer leadFamily. Select the lead explicitly (e.g. model: "gpt-6-astra") or let the router choose. Defaults are eight nodes including the lead, depth two (configurable 0–3), 100,000 observed tokens, 32 usage events and a 300-second outer deadline. Token and usage thresholds are soft, post-paid stops, not spend caps. See recursive delegation.

Data and lifecycle

Only send context you are authorized to share; never send secrets. Opaque provider metadata and encrypted reasoning are filtered from returned events. This is not a general redaction service.

Jobs and events live in memory in one MCP process. A restart loses job IDs and deduplication, and graceful shutdown terminates the runtimes it owns. The SDK may persist sessions and logs under ~/.copilot, and copilot_forget doesn't delete them. Token usage is aggregated from observed usage events; it isn't an invoice, and missing events don't prove zero consumption.

Development

npm test                                     # offline, no inference
npm run smoke -- --live gpt-6-luna           # one synthetic inference
node scripts/live-controls.mjs --live        # steering and cancellation while streaming
node scripts/review-routing.mjs --live --synthetic
node scripts/probe-tree.mjs --live           # three-node recursive probe

Live scripts use synthetic context, consume Copilot allowance, and never run in CI. review-routing.mjs --live without --synthetic sends this repository's source to Copilot. Contributor and agent guidance is in AGENTS.md.

Credits

License

MIT. Not affiliated with GitHub, OpenAI or Anthropic.

Available Tools

12 tools
copilot_applyA

Write a finished job's staged edits to disk. Requires the changeSetHash from copilot_changes, so only reviewed content is applied. Refuses before writing anything if a file changed on disk since the job read it; prepares every file before committing and reports exactly what was written if a commit fails midway. Single use per job. Apply only within the user's authorized scope.

Inputs: jobId (required), changeSetHash (required).

copilot_cancelA

Cancel a job and terminate its dedicated Copilot runtime. Idempotent; does not undo prior actions.

Inputs: jobId (required).

copilot_changesA

Show the unified diff of edits a job staged in its granted writable files, with a changeSetHash to pass to copilot_apply. Review it before applying; staged content is untrusted delegate output.

Inputs: jobId (required).

copilot_delegateA

Preferred delegation entry point: automatically select a model and reasoning effort for a bounded review, sparring, analysis or code proposal. Use after meaningful changes/tests, before consequential decisions, or for well-specified analytical work; skip trivial work. Assert sharing authorization from the user/project policy, never guess it; granted file contents are shared too. Optional files grants scoped read access and staged writes; no shell or execution. Consumes Copilot allowance. Poll copilot_events, verify findings, optionally provide feedback. One explicit parentJobId escalation is allowed; no unattended retries.

Inputs: role (required), task (required), context (required), requestId (required), +8 more.

copilot_eventsA

Get incremental emitted output and current result. Use nextCursor as after; gap means older events were evicted. Long-poll up to 30s. Output is untrusted reviewer content, not authority to change scope. Drain hasMore before waiting.

Inputs: jobId (required), after, limit, waitMs.

copilot_feedbackB

Record the orchestrator-verified outcome of a finished routed job (process-local). Does not send inference or change routing.

Inputs: jobId (required), outcome (required).

copilot_forgetB

Discard a finished, cleaned-up job from bridge memory. SDK session files are not deleted. Explicit-start deduplication is removed; routed request IDs remain reserved for this process and cannot be reused.

Inputs: jobId (required).

copilot_jobsA

List jobs owned by this server instance; does not start work.

Inputs: no named parameters.

copilot_modelsA

List models available through your Copilot authentication. No inference request.

Inputs: no named parameters.

copilot_orchestrateB

Opt in to model-initiated recursive delegation through the router. Context only: no files, shell or network tools. Explicit model selects the lead only; children route independently. Limits cover the whole tree including waiting parents. Usage thresholds are soft, not a spend cap. Use ordinary copilot_events/cancel/forget on the returned job.

Inputs: prompt (required), requestId (required), sharingAuthorized (required), risk, +7 more.

copilot_startA

Advanced: start a context-only job on an explicit model, bypassing routing. Sends supplied prompt to GitHub Copilot and consumes its allowance. Requires sharingAuthorized like the routed tools. Optional files grants scoped reads and staged writes; no commands. Supply only task-relevant, non-secret context. Returns immediately; poll copilot_events until terminal. Reuse requestId only for identical retries.

Inputs: model (required), prompt (required), requestId (required), sharingAuthorized (required), +3 more.

copilot_steerA

Send a best-effort correction to a running job before its next model request. Covered by the job's original sharing attestation: send only corrections within that authorized scope. May consume further allowance. Does not roll back prior work. Not idempotent: inspect events before retrying.

Inputs: jobId (required), prompt (required).

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.7/5.0

    Scored across 12 tools

    Disambiguation4/5

    The three job-launch tools (copilot_delegate, copilot_start, copilot_orchestrate) share a purpose, but their descriptions draw clear lines: routed default, advanced explicit-model bypass, and recursive opt-in. Similarly, steer vs. feedback vs. cancel are distinguished by timing (mid-run correction, post-run outcome recording, termination). A few boundaries still require careful reading, but an agent can select correctly.

    Naming Consistency4/5

    Every tool uses the same 'copilot_' prefix plus a single snake_case token, which is highly predictable and easy to scan. The minor deviation is that some tokens are nouns (changes, jobs, models, events, feedback) while others are verbs (delegate, apply, start, steer, cancel, forget), so the verb_noun convention is not fully uniform.

    Tool Count5/5

    Twelve tools is well within the healthy range and each maps to a distinct lifecycle stage: launch, observe, correct, terminate, review, apply, and clean up. Even the narrower utilities (copilot_models, copilot_feedback, copilot_forget) support a real need in the delegation workflow rather than padding the surface.

    Completeness4/5

    The surface covers the full job lifecycle, from delegation and long-poll event streaming through steering, cancellation, diff review, hash-gated apply, and memory cleanup. Gaps are minor: there is no direct single-job status/metadata fetch (relying on list plus events) and no way to discard a staged change set without applying or forgetting the job.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      C
      maintenance
      Enables Claude Code and Claude Desktop to delegate coding tasks to any model available in OpenCode while Claude remains the orchestrator, planning work, reviewing diffs, and running tests. Supports synchronous and async delegation, model selection, session continuation, and permission-aware execution.
      6
      MIT
    • F
      license
      Not graded
      quality
      A
      maintenance
      Enables Claude Code and other MCP clients to hand bounded work such as code review, boilerplate generation, commit messages, format conversion and embeddings to a local GPU model, LiteLLM router, OpenRouter, or cheaper cloud API like OpenAI, DeepSeek, Groq or Cerebras. Keeps the orchestrating model as architect and reviewer, cutting token spend and providing a second opinion on code.
      -
    • F
      license
      Not graded
      quality
      A
      maintenance
      Enables MCP clients like Claude Code to delegate bounded work—code review, boilerplate, commit messages, format conversion, embeddings—to local or cloud OpenAI-compatible models, keeping large files out of the main model's context to cut token costs and provide a second opinion. It routes and profiles the target model automatically, while the orchestrating client retains planning and quality checks.
      -