OpenAPI Gateway for Chat

Expose remote REST APIs to AI agents in VS Code as native language model tools. Register APIs with OpenAPI 3.0/3.1 specifications via extension commands; the extension registers language model tools (vscode.lm) that let Copilot Chat agents and other language model consumers progressively discover and invoke those APIs.
Why this extension exists
The same use case is achievable today with MCP servers derived from OpenAPI specs, which VS Code supports natively. However, there are two practical limitations:
- Deriving, hosting, and running MCP servers per API may be considered an operational burden.
- Some users working in enterprise environments lack permission to enable/use MCP servers in VS Code.
The extension is therefore a convenience layer: no external processes, no extra infrastructure — registration happens entirely inside the editor.
Features
- Register APIs from a URL or workspace file (OpenAPI 3.0.x / 3.1.x), persisted globally across workspaces.
- Progressive disclosure discovery tools:
gateway_list_apis → gateway_describe_api → gateway_list_api_operations → gateway_describe_api_operation.
- Invocation tool:
gateway_invoke_operation with structured tool input validation against the spec; supports body (inline) or bodyFile (local file path/file:// URI, absolute or workspace-relative) for request bodies, with size-aware handling and Content-Type inference.
- Safe by default: non-safe HTTP methods require explicit user confirmation before each call, with redacted auth preview and a body preview (
Body: + pretty-printed JSON or File: <path> (<size> bytes) for bodyFile).
- Header-only static auth (
none / bearer / API key in custom header), stored securely in VS Code SecretStorage.
- Uniform response serving: every HTTP response arrives as a plain-text metadata part (raw HTTP head: bare status line, headers, blank line) that is always present, plus — only when there is a body — a body part routed by content type (skips the body part for empty
204/404 etc.).
See docs/index.md for the full software specification.
Commands
All commands live under the OpenAPI Gateway category:
| Command |
Purpose |
OpenAPI Gateway: Register API from URL |
Fetch an OpenAPI JSON document over http(s) and register it. |
OpenAPI Gateway: Register API from File |
Pick an OpenAPI JSON document from the workspace and register it. |
OpenAPI Gateway: Update API Credential |
Update the stored secret for a registered API without re-registering. |
OpenAPI Gateway: Unregister API |
Remove a registered API and its stored credential. |
OpenAPI Gateway: Refresh APIs |
Re-fetch/re-read every registered spec to pick up changes. |
Registration walkthrough
- Run one of the two register commands.
- Enter a unique API identifier (
apiId) — pre-filled from the spec title; conflicts are rejected with a prompt.
- Confirm or override the base URL used for invocations — pre-filled from the spec's first declared server; multi-server specs offer a picker first.
- Select the auth type (
None / Bearer token / API key in custom header). Bearer prompts for the token; API-key prompts for the header name (e.g. X-API-Key, validated, Authorization/Host/Content-Length rejected) then the key value. Secrets are stored in VS Code SecretStorage and never displayed again. Cancelling any step aborts registration.
Agents see five tools (names as contributed):
| Tool |
Purpose |
gateway_list_apis |
List registered APIs; entry point for discovery. |
gateway_describe_api |
Show one API's metadata and operation groups. |
gateway_list_api_operations |
List operations within a group. |
gateway_describe_api_operation |
Show one operation's parameters, request body schema, and usage examples. |
gateway_invoke_operation |
Execute an operation against the registered base URL. Accepts body (inline JSON/string) or bodyFile (local file path or file:// URI, absolute or workspace-relative, mutually exclusive with body); bodyFile bytes are sent verbatim, Content-Type inferred from spec, explicit header, or file extension (.json, .txt, .xml, .html → specific types, else application/octet-stream). |
How responses are served
Every response carrying an HTTP status is returned as one or two tool-result parts:
- Metadata — a text part containing the raw HTTP head as plain text — bare status line (
200 OK), headers in arrival order as key: value (lower-case as returned by fetch()), then a blank line (statusLine\nheaders\n\n) — so the model can read the status code and headers directly. Always present.
- Body — routed by content type — present only when there is a body (responses without a body, e.g.
204 No Content or an empty 404, return only the metadata part):
- Textual types (
text/*, application/json, +json): a text part with the UTF-8 body, served whole.
- Vision-safe images (
image/png, image/jpeg, image/gif, image/webp, image/bmp): an image LanguageModelDataPart.
- Any other binary (PDFs, octet-stream, …): written via
vscode.workspace.fs to <storageUri>/response-spills/<apiId>-<operationId>-<uuid>.<ext> — uniquely named so concurrent calls never override each other — and referenced from a text part with content type, byte size, and the absolute path. Spilled files are deleted on extension deactivation.
Non-2xx statuses are not special-cased: the model detects failure from the metadata part and receives the full error body when there is one (empty error bodies return only the metadata part). Only failures without a status — network errors — fall back to a plain text result describing the connectivity problem.
Why not return all bodies as data parts? Copilot Chat forwards only text parts and image data parts from tool results into the model prompt; other LanguageModelDataParts are silently dropped (microsoft/vscode#275300). Spill files are the only way non-image binaries can reach the agent at all.
Requirements
- VS Code with the Language Model Tools API available (
vscode.lm.tools), e.g. GitHub Copilot Chat enabled for agent tool use.
Extension Settings
This extension contributes no settings.
Development
npm install # install dependencies
npm run compile # type-check, lint, and bundle
npm test # unit suites (pure Node/mocha) + integration suites (vscode-test)
Integration tests start an ephemeral local HTTP server inside VS Code's extension host; no network access beyond 127.0.0.1 is required.
Release
Releases are tag-driven and never publish to the Visual Studio Marketplace — they only produce a VSIX attached to a GitHub release (.github/workflows/release.yml).
- Set the version in
package.json and package-lock.json (e.g. 0.1.0), following semver.
- Commit and push.
- Tag and push:
git tag v0.1.0 && git push upstream v0.1.0.
- The workflow runs the test suite, builds
openapi-gateway-for-chat-<version>.vsix with @vscode/vsce, and creates a GitHub release with the artifact and auto-generated notes.
Install the VSIX from the release with Extensions: Install from VSIX... or the VS Code CLI: code --install-extension openapi-gateway-for-chat-<version>.vsix.
Security notes
- Credentials (Bearer tokens, API keys) are kept exclusively in VS Code SecretStorage; they never appear in logs, confirmations, or tool results.
- Non-safe methods require explicit confirmation showing the resolved URL and a redacted auth preview (
Authorization: Bearer *** or <HeaderName>: ***).
- Error messages name the failing parameter or endpoint without echoing secret values.
- Agent-supplied
headers cannot override the configured auth header (Authorization always reserved, plus the custom header when set).
Limitations
- Only OpenAPI 3.0.x / 3.1.x documents in JSON format are supported; YAML specs are rejected with guidance.
- Only static header-based auth is supported (
none / bearer / API key in a single custom header); OAuth flows, cookies, query-param keys, etc. are out of scope for now. Breaking change in v0: pre-change registrations lack auth metadata and invoke unauthenticated until re-registered.
Known Issues
See the specification's Open Questions section in docs/specs/software-specification.md.