LSP & MCP Providers
Lexicons can provide editor integration through LSP (Language Server Protocol) and MCP (Model Context Protocol) contributions.
LSP Providers
Section titled “LSP Providers”Core provides LexiconIndex, lexiconCompletions and lexiconHover in
packages/core/src/lsp/lexicon-providers.ts. They are generic implementations
that work with any lexicon’s registry data:
import { LexiconIndex, lexiconCompletions, lexiconHover } from "@intentius/chant/lsp/lexicon-providers";
// The generated registry JSON: Record<className, LexiconEntry>.import lexiconData from "../generated/lexicon-my-lexicon.json";
const index = new LexiconIndex(lexiconData);
// In your completionProvider():return lexiconCompletions(ctx, index, "My resource");
// In your hoverProvider():return lexiconHover(ctx, index, myCustomHoverFormatter);The two context types come from packages/core/src/lsp/types.ts:
| Type | Fields |
|---|---|
CompletionContext | uri, content, position, wordAtCursor, linePrefix |
HoverContext | uri, content, position, word, lineText |
lexiconCompletions reads linePrefix and wordAtCursor and returns
CompletionItem[]. lexiconHover reads word, looks it up in the index, and
returns HoverInfo | undefined; its third argument is an optional
(className, entry) => HoverInfo | undefined formatter.
Completions
Section titled “Completions”The completionProvider() method on your plugin returns completion items for resource and property type names. Use lexiconCompletions to generate standard completions from your registry:
completionProvider(ctx) { return lexiconCompletions(ctx, index, "K8s resource");}See
lexicons/aws/src/lsp/completions.tsfor the AWS completion provider.
The hoverProvider() method returns hover information when users mouse over resource type constructors. Use lexiconHover with an optional custom formatter:
hoverProvider(ctx) { return lexiconHover(ctx, index, (className, entry) => { return { contents: `**${className}** — \`${entry.resourceType}\`` }; });}See
lexicons/aws/src/lsp/hover.tsfor the AWS hover provider.
MCP Contributions
Section titled “MCP Contributions”Lexicons can contribute MCP tools and resources for AI agent integration:
McpToolContribution and McpResourceContribution are defined in
packages/core/src/mcp/types.ts.
import type { McpToolContribution } from "@intentius/chant/mcp/types";
mcpTools(): McpToolContribution[] { return [ { name: "k8s:lookup-resource", description: "Look up a resource type definition", inputSchema: { type: "object" as const, properties: { name: { type: "string" } }, required: ["name"], }, async handler(params: Record<string, unknown>): Promise<unknown> { return { resourceType: String(params.name) }; }, }, ];}A tool’s handler takes Record<string, unknown> and returns Promise<unknown>.
Resources
Section titled “Resources”import type { McpResourceContribution } from "@intentius/chant/mcp/types";
mcpResources(): McpResourceContribution[] { return [ { uri: "catalog", name: "K8s Resource Catalog", description: "All available Kubernetes resource types", mimeType: "application/json", async handler(): Promise<string> { return JSON.stringify([]); }, }, ];}A resource’s handler takes no arguments and must return Promise<string>.
Serialize before returning.
Namespacing
Section titled “Namespacing”Core registers every contribution under the lexicon’s own namespace: a tool as
<lexicon>:<verb>, a resource as chant://<lexicon>/<path>. That is what an
agent sees and what the docs name, so k8s:lookup-resource above registers as
exactly that, and catalog registers as chant://k8s/catalog.
Applying the namespace is idempotent (chant #1341). namespacedToolName and
namespacedResourceUri in packages/core/src/cli/mcp/server.ts accept three
authored forms and normalize them all to one registered name:
| You write | Registers as |
|---|---|
diff | <lexicon>:diff |
<lexicon>:diff | <lexicon>:diff |
catalog | chant://<lexicon>/catalog |
<lexicon>:resource-catalog | chant://<lexicon>/resource-catalog |
chant://<lexicon>/catalog | chant://<lexicon>/catalog |
That is what lets the shared createDiffTool and createCatalogResource
helpers write their own prefix without doubling it. What does not normalize is a
URI naming a different lexicon: chant://other/x contributed by aws
registers as the unusable chant://aws/chant://other/x. chant dev check-lexicon fails any contribution whose registered name is not a single
well-formed identifier, which is exactly that case.
Conventional names
Section titled “Conventional names”Most lexicons contribute a common pair, both from the shared helpers in
lexicon-plugin-helpers.ts:
| Contribution | What it does | Lexicons |
|---|---|---|
<lexicon>:diff | Diff built output against a previous build | 12 |
chant://<lexicon>/resource-catalog | The lexicon’s resource types as JSON | 12 |
Both come from packages/core/src/lexicon-plugin-helpers.ts, so contributing
them is two lines:
import { createDiffTool, createCatalogResource } from "@intentius/chant/lexicon-plugin-helpers";
mcpTools() { return [createDiffTool(mySerializer, "Diff built output for My Lexicon", "my-lexicon")];},
mcpResources() { return [ createCatalogResource( import.meta.url, // locates src/generated/ "My Lexicon Resource Catalog", "JSON list of all supported resource types", "lexicon-my-lexicon.json", // the generated registry filename "my-lexicon", ), ];},The same module exports createSkillsLoader, which the skills() member uses.
See Skills.
The CI lexicons also ship a read-only context set, each tool answering from a
local build without touching a live forge. gitlab and forgejo contribute all
eight (checks, workflow or pipeline, references, affected,
workflow-yaml or pipeline-yaml, source, owns, compare); github
contributes the first five. A new CI lexicon should match those names rather
than invent its own. See lexicons/gitlab/src/mcp/context-tools.ts.
Next Steps
Section titled “Next Steps”Add skills for AI agent guidance, then package and publish your lexicon.