Skip to main content
Glama

๐Ÿ›ฐ๏ธ MCP for Copilot

Give Copilot hands.

A production-ready Model Context Protocol gateway. Use it as a Python library or deploy it as an OpenAI-compatible FastAPI service.

CI CodeQL PyPI Python License: MIT Coverage Ruff Docker

Quick Start ยท Installation ยท Examples ยท Architecture ยท Docs ยท Contributing


๐ŸŽฏ What is this?

Copilot is a strong reasoning assistant, but on its own it cannot read your files, query your database, or run your tools. MCP for Copilot connects it to any MCP server and puts three safety gates in front of every tool call: an allowlist, an approval layer, and argument validation.

It speaks two protocols at once โ€” MCP on the tool side, OpenAI on the client side โ€” so any OpenAI SDK client can use it as a drop-in replacement, and any MCP server can be its tool provider.


Related MCP server: LangGraph FastAPI MCP Server

โœจ Features

  • ๐Ÿ”Œ Three MCP transports โ€” stdio, http (streamable), and sse

  • ๐Ÿง  GPT-6 family aware โ€” Sol, Luna, Astra, and GPT-5.6 Sol/Luna with correct context windows, output caps, and pricing metadata

  • ๐Ÿ›ก๏ธ Three-gate tool safety โ€” allowlist โ†’ approval โ†’ dispatch, and it fails closed at every gate

  • โœ… Argument validation โ€” JSON-schema subset validation before dispatch, so a malformed call never reaches your server

  • ๐Ÿšฆ Risky-tool detection โ€” 40+ mutating verbs (write, delete, exec, โ€ฆ) are flagged automatically; unknown tools are treated as risky

  • ๐Ÿ” Secret redaction โ€” 11 regex rules scrub keys, tokens, and JWTs from every log line and error message

  • ๐Ÿงฏ Prompt-injection guard โ€” tool output is wrapped and labelled as untrusted data before it re-enters the model context

  • ๐ŸŒŠ Streaming โ€” OpenAI-compatible SSE with the exact chunk format clients expect

  • ๐Ÿณ Multi-stage Docker โ€” one image, both modes, non-root user, healthcheck

  • ๐Ÿงฉ Zero-config library mode โ€” pip install and go; no server required

  • ๐Ÿงช Typed and tested โ€” full type hints, mypy --strict, 3-layer test suite


๐Ÿš€ Quick Start

Option A โ€” Use as a library

pip install "mcp-for-copilot[library]"
import asyncio
from mcp_for_copilot import Gateway

async def main():
    async with Gateway() as gateway:
        result = await gateway.chat([
            {"role": "user", "content": "List the files in the current directory."}
        ])
        print(result.content)
        print("tools used:", result.used_tools)

asyncio.run(main())

Option B โ€” Deploy as a server

pip install "mcp-for-copilot[server]"
export LLM_API_KEY=sk-...
mcp-for-copilot serve
curl http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model": "gpt-6-sol", "messages": [{"role": "user", "content": "Hello!"}]}'

That is the whole setup. Any OpenAI SDK client works against it unchanged.


๐Ÿ“ฆ Installation

pip

# Library only โ€” talk to an MCP server from your own code
pip install "mcp-for-copilot[library]"

# Server โ€” FastAPI gateway + stdio MCP server
pip install "mcp-for-copilot[server]"

# Everything
pip install "mcp-for-copilot[all]"

Docker

docker run --rm -p 8000:8000 \
  -e LLM_API_KEY=sk-... \
  ghcr.io/rwamyth-blip/mcp-for-copilot:latest

From source

git clone https://github.com/rwamyth-blip/mcp-for-copilot.git
cd mcp-for-copilot
pip install -e ".[all,dev]"
cp .env.example .env   # then edit .env

๐Ÿ’ก Usage Examples

1. Library โ€” chat with tools, with an audit trail

import asyncio
from mcp_for_copilot import Gateway

async def main():
    async with Gateway() as gateway:
        result = await gateway.chat(
            [{"role": "user", "content": "How many documents are in the users collection?"}],
            system="You are a helpful data assistant.",
        )

        print(result.content)
        for call in result.invocations:
            status = "ok" if call["executed"] and not call["is_error"] else "blocked"
            print(f"  [{status}] {call['tool']} โ€” {call['reason']}")

asyncio.run(main())

2. Server โ€” OpenAI SDK, unchanged

from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="not-needed-locally")

response = client.chat.completions.create(
    model="sol",  # alias for gpt-6-sol
    messages=[{"role": "user", "content": "Summarise README.md"}],
)
print(response.choices[0].message.content)

3. Custom approval policy โ€” approve only what you trust

import asyncio
from mcp_for_copilot import Gateway, static_approver

async def main():
    approver = static_approver(allow=["write_file"], deny=["delete_file"])
    async with Gateway(approver=approver) as gateway:
        result = await gateway.chat([
            {"role": "user", "content": "Write 'hello' to notes.txt"}
        ])
        print(result.content)

asyncio.run(main())

4. CLI โ€” one-shot prompt

mcp-for-copilot chat "What models do you support?" --json
mcp-for-copilot models
mcp-for-copilot status

๐Ÿ—๏ธ Architecture

flowchart LR
    subgraph Client["Client side"]
        A["OpenAI SDK<br/>/ any HTTP client"]
        B["Your Python code"]
    end

    subgraph Gateway["mcp-for-copilot"]
        C["FastAPI app<br/>/v1/chat/completions"]
        D["Gateway facade"]
        E["Orchestrator<br/>model โ†’ tool โ†’ model"]
        F["ToolRouter<br/>allowlist + schema"]
        G["ApprovalLayer<br/>fail closed"]
        H["LLMProvider<br/>OpenAI adapter"]
        I["MCPClient<br/>stdio / http / sse"]
    end

    subgraph Tools["Tool side"]
        J["MCP server"]
        K["Files, DB, APIs"]
    end

    L["GPT-6 Sol"]

    A --> C --> D --> E
    B --> D
    E --> H --> L
    E --> F --> G --> I --> J --> K
    J -. "tool schemas" .-> F

The three gates

Every tool call the model requests must pass all three, in order:

Gate

Component

Behaviour on failure

1. Allowlist

ToolRouter.route()

Denied โ€” reported to the model as an error result

2. Approval

ApprovalLayer.request()

Denied โ€” fails closed when no approver is configured

3. Dispatch

MCPClient.call_tool()

Error captured and returned; the turn continues

A denied tool never aborts the turn. The model is told why it was denied and can explain the outcome or try a different approach.

Why reasoning_effort is forced to none with tools

The GPT-6 family rejects function tools combined with reasoning_effort on /v1/chat/completions:

Function tools with reasoning_effort are not supported for gpt-6-luna in /v1/chat/completions. To use function tools, use /v1/responses or set reasoning_effort to 'none'.

The field must be present and set to "none" โ€” omitting it is also rejected. Since tool calling is the entire point of this package, the provider adapter sends "none" whenever tools are present, and forwards your configured effort unchanged when they are not.


โš™๏ธ Configuration

All configuration is environment-driven. See .env.example for the annotated list.

Variable

Default

Description

LLM_API_KEY

(empty)

Required. Provider API key.

LLM_MODEL_ID

gpt-6-sol

Model id or alias.

LLM_BASE_URL

https://api.openai.com/v1

OpenAI-compatible base URL.

LLM_REASONING_EFFORT

(empty)

none/low/medium/high/xhigh/max.

MCP_SERVER_URL

(empty)

Command (stdio) or URL (http/sse).

MCP_TRANSPORT

stdio

stdio, http, or sse.

MCP_REQUIRE_APPROVAL

true

Require approval for risky tools.

MCP_ALLOWED_TOOLS

(empty)

Comma-separated allowlist; empty = read-only defaults.

MCP_MAX_TOOL_ROUNDS

5

Cap on model โ†’ tool โ†’ model rounds.

GATEWAY_API_KEY

(empty)

When set, /v1/* requires Authorization: Bearer.

GATEWAY_PORT

8000

Bind port.

Supported models

Model

Tier

Context

Max output

Input / Output per Mtok

gpt-6-astra

flagship

1.05M

128K

$10 / $50

gpt-6-sol

balanced

1.05M

128K

$2 / $10

gpt-6-luna

efficient

1.05M

128K

$0.10 / $0.50

gpt-5.6-sol

flagship

1.05M

128K

$4 / $20

gpt-5.6-luna

efficient

1.05M

128K

$0.20 / $1.20

Aliases: gpt-6, gpt6, sol โ†’ gpt-6-sol ยท luna โ†’ gpt-6-luna ยท astra โ†’ gpt-6-astra ยท gpt-5.6 โ†’ gpt-5.6-sol


๐Ÿณ Docker

# Gateway mode (default)
docker compose up gateway

# stdio MCP server mode
docker compose up mcp

# Both
docker compose up

The image is multi-stage: dependencies are built in a builder stage, and the runtime stage runs as a non-root user with a HEALTHCHECK on /health.


๐Ÿงช Testing

make test          # pytest with coverage
make lint          # ruff check + format check
make typecheck     # mypy --strict
make check         # all of the above

Tests are split into three layers:

Layer

Path

What it covers

Unit

tests/unit/

provider, mcp_client, tool_router, approval, config

Integration

tests/integration/

gateway.app routes, gateway.server tools

End-to-end

tests/e2e/

Full model โ†’ tool โ†’ model loop with a fake MCP server

No test touches the network: httpx transports and the MCP client are injected.


๐Ÿ“š Documentation

Full documentation lives at rwamyth-blip.github.io/mcp-for-copilot.


๐Ÿค Contributing

Contributions are welcome. Please read CONTRIBUTING.md and CODE_OF_CONDUCT.md first.

git clone https://github.com/rwamyth-blip/mcp-for-copilot.git
cd mcp-for-copilot
pip install -e ".[all,dev]"
pre-commit install
make check

Good first issues are labelled good first issue.


๐Ÿ” Security

Please do not open a public issue for a vulnerability. See SECURITY.md for the private disclosure process.

This package never logs a credential: every log line and error message passes through mcp_for_copilot.logging_utils.redact().


๐Ÿ“„ License

MIT ยฉ VihokAI


โญ Star History

โฌ† back to top

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI agents to access a unified catalog of tools from various APIs (OpenAPI, GraphQL, MCP, Google Discovery) through the MCP protocol.
    173 npm
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables an LLM to dynamically discover and call tools across multiple MCP servers (file, GitHub, SQL, Python execution) with authentication, rate limiting, and observability, supporting parallel execution and secure deployment.
    -