Copilot Proxy is a Visual Studio Code extension that exposes the VS Code Language Model API through an OpenAI-compatible Express server. This project is intended for research, experimentation, and local prototyping rather than production use.
This project is not affiliated with GitHub, Microsoft, or OpenAI.
Current GitHub Copilot model availability depends on your subscription and the VS Code Language Model API.
This repository is a rebranded and maintained fork of the original copilot-proxy project by Lutz Leonhardt.
Special thanks to Lutz Leonhardt for creating the original project and publishing it under the MIT License, which made this fork, rebranding, and continued maintenance possible.
- Start and stop the local proxy server from inside VS Code.
- Configure the listening port through settings or a command.
- Forward chat requests with streaming and non-streaming support.
- Protect the proxy with locally stored API tokens.
- Expose OpenAI-compatible endpoints for models, chat completions, responses, and related assistant routes.
- Download the latest
.vsixpackage from the GitHub Releases page. - Open Visual Studio Code.
- Open the Extensions view (
Cmd+Shift+Xon macOS orCtrl+Shift+Xon Windows/Linux). - Open the extensions menu (
...) and choose Install from VSIX.... - Select the downloaded
.vsixfile. - Reload VS Code if prompted.
The extension exposes one primary setting:
copilotProxy.port— default:3000
You can change it either:
- in the VS Code Settings UI by searching for
Copilot Proxy, or - from the Command Palette with Copilot Proxy: Configure Port.
The extension includes token management commands so you can lock down your local proxy.
- Create a token with Copilot Proxy: Create API Token.
- List saved tokens with Copilot Proxy: List API Tokens.
- Remove a token with Copilot Proxy: Remove API Token.
Tokens are stored in VS Code global state and reused across sessions.
When at least one token exists, requests must include a bearer token in the Authorization header:
curl -H "Authorization: Bearer cpx_your_token_here" \
-H "Content-Type: application/json" \
-d '{"model": "gpt-4o", "messages": [{"role": "user", "content": "Hello"}]}' \
http://localhost:3000/v1/chat/completionsIf no tokens have been created, authentication is disabled and the server accepts requests without token validation.
- Run Copilot Proxy: Start Server from the Command Palette.
- The server starts on the configured port, which defaults to
3000.
- Run Copilot Proxy: Stop Server from the Command Palette.
On the first model request, VS Code may ask you to grant permission for this extension to access the Language Model API. Accept the prompt so requests can complete successfully.
The proxy exposes OpenAI-style model discovery at /v1/models.
GET /v1/modelsreturns all chat models plus any embedding models exposed by VS Code.GET /v1/models?type=chatreturns only chat-capable models.GET /v1/models?type=embeddingreturns only embedding models.
Example requests:
curl http://localhost:3000/v1/modelscurl http://localhost:3000/v1/models?type=chatcurl http://localhost:3000/v1/models?type=embeddingThe proxy also exposes POST /v1/embeddings and forwards requests to the VS Code embeddings API:
curl -X POST http://localhost:3000/v1/embeddings \
-H "Authorization: Bearer cpx_your_token_here" \
-H "Content-Type: application/json" \
-d '{
"model": "text-embedding-3-small",
"input": "hello world"
}'If model is omitted, the proxy uses the first embedding model reported by VS Code.
Embedding support depends on the VS Code Embeddings proposed API. That means chat completions can work while embedding discovery and /v1/embeddings do not.
This repository already declares the proposal in package.json via enabledApiProposals, but the runtime extension you have loaded must also include that manifest entry.
If GET /v1/models?type=embedding returns an empty list, or POST /v1/embeddings returns a 501 error, check the following:
- You are running the latest build of this extension, not an older installed VSIX.
- VS Code has been reloaded after installing or rebuilding the extension.
- Your VS Code build supports the embeddings proposal.
- If your setup requires it, start VS Code with:
code --enable-proposed-api hyorman.copilot-proxyWhen the proposal is unavailable, the proxy degrades gracefully:
GET /v1/modelsstill lists chat models.GET /v1/models?type=embeddingreturns no embedding entries.POST /v1/embeddingsreturns a clear error instead of a generic server failure.
This repository is distributed under the MIT License. The upstream copyright notice is retained as required by the license.
The extension exposes an OpenAI-compatible Skills API at /v1/skills. Skills are versioned file bundles anchored by a SKILL.md manifest.
Every bundle must include exactly one SKILL.md file with YAML frontmatter:
---
name: My Skill
description: One-line summary of the skill
---
Detailed instructions for the agent go here.Additional files (code, data, configs) can be included alongside the manifest.
| Method | Path | Description |
|---|---|---|
POST |
/v1/skills |
Create a skill from multipart or zip upload |
GET |
/v1/skills |
List skills (paginated) |
GET |
/v1/skills/:id |
Retrieve a skill |
POST |
/v1/skills/:id |
Update default version or metadata |
DELETE |
/v1/skills/:id |
Delete a skill and its files |
POST |
/v1/skills/:id/versions |
Upload a new version |
curl -X POST http://localhost:3000/v1/skills \
-H "Authorization: Bearer cpx_your_token" \
-F "files[]=@SKILL.md" \
-F "files[]=@helper.py"Or upload a zip archive:
curl -X POST http://localhost:3000/v1/skills \
-H "Authorization: Bearer cpx_your_token" \
-F "files=@my-skill.zip"curl -X POST http://localhost:3000/v1/skills/skill_abc123/versions \
-H "Authorization: Bearer cpx_your_token" \
-F "files[]=@SKILL.md" \
-F "files[]=@updated_helper.py"curl -X POST http://localhost:3000/v1/skills/skill_abc123 \
-H "Authorization: Bearer cpx_your_token" \
-H "Content-Type: application/json" \
-d '{"default_version": 2}'Attach skills to a /v1/responses request via the skills field. You can use registered skill references or inline skills.
Skill reference (uses a skill registered via /v1/skills):
curl -X POST http://localhost:3000/v1/responses \
-H "Authorization: Bearer cpx_your_token" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o",
"input": "Write a Python function to sort a list.",
"skills": [
{ "type": "skill_reference", "skill_id": "skill_abc123" }
]
}'Specific version:
{ "type": "skill_reference", "skill_id": "skill_abc123", "version": 2 }Inline skill (base64-encoded content, no registration required):
curl -X POST http://localhost:3000/v1/responses \
-H "Authorization: Bearer cpx_your_token" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o",
"input": "Refactor this code.",
"skills": [
{
"type": "inline",
"name": "Code Style",
"description": "Enforce coding standards",
"source": {
"type": "base64",
"media_type": "text/markdown",
"data": "QWx3YXlzIHVzZSBUeXBlU2NyaXB0IHN0cmljdCBtb2Rl"
}
}
]
}'Skills can be attached to assistants and runs. When a run executes, skill instructions are resolved and injected into the system prompt alongside the assistant's instructions.
curl -X POST http://localhost:3000/v1/assistants \
-H "Authorization: Bearer cpx_your_token" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o",
"name": "My Coding Assistant",
"instructions": "You are a helpful coding assistant.",
"skills": [
{ "type": "skill_reference", "skill_id": "skill_abc123" }
]
}'Skills specified on a run override the assistant's skills for that run:
curl -X POST http://localhost:3000/v1/threads/thread_abc123/runs \
-H "Authorization: Bearer cpx_your_token" \
-H "Content-Type: application/json" \
-d '{
"assistant_id": "asst_abc123",
"skills": [
{ "type": "skill_reference", "skill_id": "skill_xyz789", "version": "latest" }
]
}'If no skills are specified on the run, the assistant's skills are used. If the run specifies an empty skills array, no skills are injected.
curl -X POST http://localhost:3000/v1/threads/runs \
-H "Authorization: Bearer cpx_your_token" \
-H "Content-Type: application/json" \
-d '{
"assistant_id": "asst_abc123",
"thread": {
"messages": [{ "role": "user", "content": "Help me write tests." }]
},
"skills": [
{ "type": "skill_reference", "skill_id": "skill_abc123" },
{
"type": "inline",
"name": "Test Style",
"description": "Testing conventions",
"source": {
"type": "base64",
"media_type": "text/markdown",
"data": "VXNlIGRlc2NyaWJlL2l0IGJsb2NrcyB3aXRoIHZpdGVzdA=="
}
}
]
}'curl -X POST http://localhost:3000/v1/assistants/asst_abc123 \
-H "Authorization: Bearer cpx_your_token" \
-H "Content-Type: application/json" \
-d '{
"skills": [
{ "type": "skill_reference", "skill_id": "skill_new456" }
]
}'