Creating a provider

Providers can be implemented:

  • as an HTTP endpoint
  • as a JavaScript file (with a default export)

HTTP providers

An OpenCtx provider can be implemented as an HTTP server that implements the provider API and is available at any URL.

JavaScript providers

For convenience, you can also just bundle and publish a .js file that implements the simple @openctx/provider TypeScript API (as a default export):

import type {
AnnotationsParams, AnnotationsResult,
MentionsParams, MentionsResult,
MetaParams, MetaResult,
ItemsParams, ItemsResult, Provider,
} from '@openctx/provider'
export default {
meta(params: MetaParams): Promise<MetaResult> { /* ... */ }
mentions(params: MentionsParams): Promise<MentionsResult> { /*... */ }
items(params: ItemsParams): Promise<ItemsResult> { /* ... */ }
annotations(params: AnnotationsParams): Promise<AnnotationsResult> { /*... */ }
} satisfies Provider

Then use the URL (file:// or https://) to that .js file. This way, you don't need to deploy a public HTTP server for the provider. See the playground for live examples.

Using providers published to npm

For convenience, the URL serves the contents of the named npm package's main file.

For example, suppose you have an npm package @openctx/provider-hello-world published with the following package.json:

"name": "@openctx/provider-hello-world",
"main": "index.js",
// ...

You can configure that provider in an OpenCtx client like so:

"openctx.providers": {
"": true

When developing locally, configure your provider in the client (e.g., VS Code) by using the path to the bundled .js file:

"openctx.providers": {
"file:///<path/to/js/bundle>/index.js": true,

The package's index.js file is loaded and expected to have a single default export that satisfies the Provider interface.

See the source code for the Hello World provider for a full example.

Bundling provider packages

The above example works for simple providers written in a single JavaScript file, with no build step or dependencies. For providers written in TypeScript, implemented across multiple source files, or that have dependencies, you need to bundle the provider to a single JavaScript file (ESM).

Here's an example package.json for this slightly more complex provider:

"name": "@openctx/provider-web",
"type": "module",
"main": "dist/bundle.js",
"types": "dist/index.d.ts",
"files": ["dist/bundle.js", "dist/index.d.ts"],
"sideEffects": false,
"scripts": {
"bundle": "tsc --build && esbuild --log-level=error --bundle --format=esm --outfile=dist/bundle.js index.ts",
"prepublishOnly": "tsc --build --clean && npm run --silent bundle"
"dependencies": {
"@openctx/provider": "*"
"devDependencies": {
"esbuild": "*",
"typescript": "*"

See the source code for the web page context provider for a full example.