Skip to main content
Glama
jurulabs

MCP Model Bridge

by jurulabs

MCP Model Bridge

Runs an agent definition from .github/agents/ against a model you name, instead of the one the IDE session happens to use.

Copilot agent definitions carry no model field, so a subagent inherits the session model. This server closes that gap: it reads the agent file, uses its body as the system prompt, and executes a bounded tool loop against a chosen model.

Project-independent. Nothing here is tied to the repository it was developed in. Point it at any project and it picks up that project's agents and that project's model policy.

Status

MVP. Ships with a mock gateway so the wiring is testable without credentials. Point it at a real endpoint with two environment variables.

Related MCP server: act-mcp

Install

The bridge is a developer tool, not a runtime dependency. Install it once, use it everywhere.

# from a checkout
npm install
npm run build
npm link
# or straight from a git remote, once the package lives in its own repo
npm install -g git+https://github.com/<you>/mcp-model-bridge.git
# or from a registry, if you publish it
npm install -g @jurulabs/mcp-model-bridge

All three put mcp-model-bridge on the PATH.

Quick start

npm run smoke

The smoke test spawns the built server against a fixture project under test/fixture-workspace that has nothing to do with the surrounding repository. It asserts that the bridge discovers that project's agents and policy, and that the same agent reports different models on different tiers.

Point it at a real project instead:

node scripts/smoke-test.mjs C:\path\to\any\project

Configuration

Variable

Default

Purpose

BRIDGE_WORKSPACE_ROOT

process.cwd()

The host project. Root for path confinement and tool access.

BRIDGE_AGENTS_DIR

<root>/.github/agents

Where agent definitions live

BRIDGE_MODEL_POLICY

auto-discovered

Tier map and allow-list

BRIDGE_GATEWAY_URL

(unset → mock)

Endpoint base URL

BRIDGE_GATEWAY_TOKEN

(unset → mock)

Credential, read from the environment only

BRIDGE_GATEWAY_SCHEMA

anthropic-messages

anthropic-messages or openai-chat

BRIDGE_GATEWAY_AUTH

per schema

x-api-key or bearer

In practice only BRIDGE_WORKSPACE_ROOT needs setting. Everything else is discovered.

With BRIDGE_GATEWAY_URL and BRIDGE_GATEWAY_TOKEN unset, the server runs the mock gateway and reports gateway: mock. A half-configured gateway also reports mock, which surfaces the missing variable instead of hiding it behind a confident label.

Where the gateway values come from

Not from GitHub Copilot. The Copilot subscription has no endpoint you can post arbitrary requests to, so it cannot serve as the gateway. The two values come from an inference provider you hold credentials with, billed separately from Copilot. That second cost centre is the price of choosing the model yourself.

The client speaks two request shapes, selected by BRIDGE_GATEWAY_SCHEMA:

Schema

Path appended to the base URL

Default auth

anthropic-messages (default)

/v1/messages

x-api-key

openai-chat

/v1/chat/completions

bearer

A base URL that already ends in /v1 is not doubled, so whichever form the provider documents can be pasted as-is.

OpenRouter — one key, every model

The best fit for this bridge, because the tier idea only pays off when cheap, default and strong can point at different vendors behind a single credential.

Variable

Value

BRIDGE_GATEWAY_URL

https://openrouter.ai/api/v1

BRIDGE_GATEWAY_TOKEN

a key from openrouter.ai → Keys

BRIDGE_GATEWAY_SCHEMA

openai-chat

BRIDGE_GATEWAY_AUTH

leave unset — openai-chat already defaults to bearer

OpenRouter is prepaid: top up credits, then spend per token. Model identifiers are vendor-prefixed, anthropic/…, openai/…, google/…. List the current ones and their prices before writing the policy:

(Invoke-RestMethod https://openrouter.ai/api/v1/models).data |
  Select-Object id, @{n='in';e={$_.pricing.prompt}}, @{n='out';e={$_.pricing.completion}} |
  Sort-Object in

Two caveats worth knowing up front. OpenRouter may route a model across several upstream providers with differing context limits and latency — pin one with the :nitro or provider-routing suffixes if that matters. And the bridge's text tool protocol is unaffected either way, since it never relies on native tool calling.

Anthropic directly

Variable

Value

BRIDGE_GATEWAY_URL

https://api.anthropic.com

BRIDGE_GATEWAY_TOKEN

a key from console.anthropic.com → Settings → API Keys

BRIDGE_GATEWAY_SCHEMA

leave unset

BRIDGE_GATEWAY_AUTH

leave unset — Anthropic expects x-api-key

Needs a paid Anthropic account with credit; the key is shown once at creation.

A corporate or self-hosted gateway

Variable

Value

BRIDGE_GATEWAY_URL

the base path the gateway documents

BRIDGE_GATEWAY_TOKEN

issued by that gateway's portal, not by the model vendor

BRIDGE_GATEWAY_SCHEMA

whichever shape it exposes

BRIDGE_GATEWAY_AUTH

usually bearer — these normally sit behind an OAuth proxy

Confirm in the gateway's own documentation which schema it speaks and which model identifiers it accepts.

A translating proxy

Run LiteLLM locally and it fronts OpenAI, Azure OpenAI, Bedrock or Vertex behind either schema. BRIDGE_GATEWAY_URL = http://localhost:4000, token = the master key you set in the proxy config, auth bearer. The upstream provider key then lives in the proxy config, not in this bridge.

Model identifiers are the usual trip-hazard

The bundled policy names Copilot picker labels such as claude-sonnet-5. No provider API recognises those. Replace them with the identifiers your gateway accepts, in the host project's .github/model-policy.json. For OpenRouter that means vendor-prefixed ids:

{
  "tiers": {
    "cheap": "<vendor>/<small model>",
    "default": "<vendor>/<mid model>",
    "strong": "<vendor>/<large model>"
  },
  "allowedModels": ["<vendor>/<small model>", "<vendor>/<mid model>", "<vendor>/<large model>"]
}

A model outside the allow-list is refused, so a stale identifier fails at once rather than after a billed call.

Supplying the values

Per session:

$env:BRIDGE_GATEWAY_URL = 'https://openrouter.ai/api/v1'
$env:BRIDGE_GATEWAY_TOKEN = '<key>'
$env:BRIDGE_GATEWAY_SCHEMA = 'openai-chat'

Persistently for your user account:

[Environment]::SetEnvironmentVariable('BRIDGE_GATEWAY_TOKEN', '<key>', 'User')

Never in the repository, never in the agent file, never in the policy file.

Proving the gateway answers

The smoke test only exercises the mock. One real call, costing one short completion:

npm run gateway:check -- <model-id>

It prints the resolved endpoint, schema and auth scheme, then the model's own reply. The three things that can only fail live — credentials, schema, model identifier — all surface here rather than mid-session.

Inside the IDE, list_agents reports the same resolution without ever echoing the token:

gateway: http (https://openrouter.ai/api/v1/chat/completions, schema: openai-chat, auth: bearer)

gateway: mock means one of the two required variables did not reach the process.

Model policy

The policy file holds the tier map and the allow-list:

{
  "tiers": { "cheap": "gpt-5.6-luna", "default": "claude-sonnet-5", "strong": "claude-opus-5" },
  "allowedModels": ["gpt-5.6-luna", "claude-sonnet-5", "claude-opus-5"]
}

It is looked up in this order:

  1. BRIDGE_MODEL_POLICY, if set

  2. <workspaceRoot>/.github/model-policy.json — the host project's own policy

  3. the bundled model-policy.json — so a fresh project needs no setup

list_agents reports which one won, as source: explicit | workspace | bundled.

A model outside allowedModels is refused with an explicit error. Silent fallback to an expensive model is the failure mode that costs money without anyone noticing, so it is not offered.

Tools

run_agent

Parameter

Required

Meaning

agent

yes

File stem under the agents directory, e.g. Explorer

task

yes

The instruction, including the desired output contract

model

no

Tier name (cheap, default, strong) or an allow-listed model id

maxRounds

no

Tool rounds before stopping, default 4, ceiling 10

Returns the agent's output followed by a provenance block:

agent: Explorer
model used: gpt-5.6-luna (tier: cheap)
rounds: 2, tool calls: 1
stopped: completed

The provenance block is the point of the exercise. A bridge that runs but reports the session model has failed at the only thing it exists to do.

list_agents

Reports the agents the host project defines, the agents directory, the active policy file and where it came from, the tier map, the allow-list, and whether the gateway is live or mocked.

agents directory: C:\some\project\.github\agents
agents: Explorer, Reviewer, ShopifyApi, Tester
model policy: C:\some\project\.github\model-policy.json (source: workspace)
tiers: cheap -> gpt-5.6-luna, default -> claude-sonnet-5, strong -> claude-opus-5
allowed models: gpt-5.6-luna, claude-sonnet-5, claude-opus-5
gateway: mock

A project with no agents directory reports agents: (none found) rather than failing, so the tool can still explain the rest of the configuration.

Registering in JetBrains

Settings → Tools → GitHub Copilot → Model Context Protocol (MCP)

{
  "servers": {
    "model-bridge": {
      "command": "mcp-model-bridge",
      "env": {
        "BRIDGE_WORKSPACE_ROOT": "C:\\path\\to\\the\\project\\you\\are\\working\\in"
      }
    }
  }
}

If you did not link the binary onto the PATH, call the entry point directly instead:

{
  "command": "node",
  "args": ["C:\\path\\to\\mcp-model-bridge\\dist\\index.js"]
}

Run npm run build first — the entry point is the compiled dist/index.js.

Safety

  • Read-only toolset. read_file and grep_search only; a cheap model driving these tools cannot edit anything.

  • Path confinement. Every requested path resolves against the workspace root; traversal is refused.

  • Round ceiling. The loop cannot run away, so it cannot spend without limit.

  • Credentials from the environment. Never from the agent file or the policy file.

  • Separate billing. Gateway calls are charged outside the Copilot subscription. Two cost centres exist; only one appears in the IDE.

Architecture

The full design, including the variants considered and why this scope was chosen, lives in the global ai-automation skill:

~/.agents/skills/ai-automation/MCP-BRIDGE.md

To move this package into its own repository, see EXTRACTION.md.

Known limits

  • Agent bodies written for richer toolsets degrade here. An agent that relies on semantic_search falls back to grep_search.

  • Two upstream schemas are implemented, Anthropic Messages and OpenAI Chat Completions. A third shape is a one-file change in src/gateway-client.ts, or a translating proxy in front of it.

  • Tool calls travel as fenced ```tool blocks rather than a native tool-calling API, which keeps the bridge portable at the cost of some reliability on weaker models.

  • Publishing under the @jurulabs scope requires owning that scope on the target registry. Git and npm link installs need no registry at all.

Available Tools

2 tools
list_agentsList the agents this bridge can runB

Reports the agents the host project offers, the model policy in force and where it came from, the tier map, the allow-list, and whether the gateway is live or mocked.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It usefully discloses return content the agent cannot get elsewhere — model policy and its provenance, tier map, allow-list, and whether the gateway is live or mocked — but never states outright that it is a read-only, side-effect-free call.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single dense sentence with no filler, and the primary subject (agents offered) is front-loaded ahead of the secondary config details. The enumerated tail is long but each item is informative.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, so the description must carry the return shape — and it does, listing the agents, model policy, tier map, allow-list, and gateway status. That is close to complete for a zero-arg read tool, though it omits go/no-go guidance against run_agent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so there is nothing for the description to disambiguate. Baseline of 4 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Reports') and resource ('the agents the host project offers'), and enumerates the ancillary data returned. It is clearly distinguishable from the sibling run_agent, though it does not name that sibling explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to call this versus run_agent, nor any stated preconditions. The only cue is the implicit read-vs-execute split between the two tool names, which the agent must infer.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

run_agentRun an agent on a chosen modelC

Executes an agent definition from the host project against a model you name. Returns the result plus the model actually used, so routing is verifiable.

ParametersJSON Schema
NameRequiredDescriptionDefault
taskYesThe instruction, including the desired output contract
agentYesFile stem under the agents directory, e.g. "Explorer"
modelNoTier name (cheap, default, strong) or an allow-listed model id
maxRoundsNoTool rounds before stopping (default 4)

TDQS

C2.9/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden. It adds only that the return includes the model actually used, but omits side effects, permissions, reversibility, and what 'executes' entails (e.g., local process, file writes).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences with no filler, and the action is front-loaded before the return detail. It is appropriately sized, though quite sparse given the amount of guidance a caller needs.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For an action tool with no annotations and no output schema, the description supplies the core purpose and partial return information but omits prerequisites, side effects, and usage context. It is minimum viable but leaves meaningful gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all four parameters are already well documented. The description does not add syntax, constraints, or meaning beyond what the schema provides, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Executes an agent definition') with scope ('from the host project against a model you name'), making the core action clear. However, it does not differentiate from the sibling tool list_agents or explicitly name it, so sibling differentiation is absent.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit when-to-use, when-not, or alternatives are provided. It implies an agent name is required but never says to use list_agents first or describes contexts where this tool is preferred over other execution approaches.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

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

  1. 2 tool updatesv0.1.0
    • First observedlist_agents
    • First observedrun_agent

TDQS

A3.5/5.0

Scored across 2 tools

Disambiguation5/5

list_agents is a read-only introspection operation and run_agent is an execution operation, targeting entirely different actions on the same domain. There is no plausible way for an agent to confuse the two.

Naming Consistency5/5

Both tools follow a clean verb_noun snake_case pattern (list_agents, run_agent) with the noun 'agent' consistent across the set. Fully predictable.

Tool Count3/5

Two tools is thin even for a narrow bridge surface; a discovery call plus a single execution call leaves little room for inspecting, validating, or managing runs. Still, both tools clearly earn their place given the stated purpose.

Completeness4/5

The pairing of discover-agents and execute-agent covers the core read/run lifecycle, and run_agent returns the model actually used, closing the routing-verification loop. Gaps are minor and largely handled outside the server (agent definitions live in the host project), though there is no status, cancel, or batch execution path.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    A
    quality
    D
    maintenance
    Exposes tools to list, run, and inspect GitHub Actions workflows locally via act, enabling debugging and fixing failures through an agent loop.
    3
    -
  • A
    license
    A
    quality
    B
    maintenance
    Enables delegating coding tasks to Cursor Cloud Agents from Claude Code, Codex, or Grok, with scoped repository access, progress monitoring, follow-ups, and result reporting.
    23
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables Claude Code to offload bounded, read-heavy tasks to external agent CLIs (agy, opencode, copilot) with preflight validation, circuit breakers, and a local dashboard for monitoring delegation and subagent activity.
    39 npm
    MIT