Skip to content
Menu

Ground AI answers in your own docs and data model

View .md
You end up withYour documents imported into a Beacon project and, in full Beacon, your DbContext exposed as a read-only data source, plus a check that an agent finds both
Timeabout 25 minutes
You needAn application with Beacon wired in (MCP gateway or Integrate Beacon), Markdown files in your repository, and for the data model part full Beacon with an EF Core DbContext and a read-only database login
Applies toBeacon 5.0 · Both. Documents: gateway and full Beacon. ExposeDbContext, the glossary and golden examples: full Beacon only, because the gateway has no data sources and no SQL tools
DecisionOptionsDefault
Where the documents liveA folder copied to the output, or embedded in the assemblyEmbedded, so the deployment cannot lose them
Expose the data modelYes (full Beacon only), or documents onlyDocuments only
Tables an agent may readAn explicit allow-listNone: ExposeDbContext is default-deny
Columns hidden or maskedExcluded (invisible) or masked (visible, values ***)Mask national ids and account numbers, exclude secrets

Each document is split into overlapping sentence windows (5 sentences, 1 overlap, by default), so a paragraph is retrieved on its own. Write for that.

  • One topic per page, with a title: in the frontmatter (else the first # heading is used).
  • Each paragraph makes sense without the paragraphs around it: name the thing in full instead of “it”.
  • Use the words your people use in questions, and say once what they mean: “active customer means …”.
  • Put definitions, rules and “where to find it” first, narrative last.
  • State units, time zones and currencies.
  • Keep each file under 512 KB (the default MaxDocumentBytes; larger files are skipped with a warning).
  • No secrets, no personal data, no real customer names. The documents are readable by every caller who can read the project.

Only .md, .markdown and .txt files are imported.

Embed them in the assembly:

<ItemGroup>
<EmbeddedResource Include="..\docs\wiki\**\*.md" LogicalName="docs/wiki/%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>

The LogicalName is required: without it MSBuild mangles folder names and joins them with dots. To copy a folder instead, see Shipping the documents.

In the gateway:

builder.Services.AddBeaconMcpGateway(builder.Configuration, x =>
{
// ...
x.Docs(y => y.FromEmbeddedResources(typeof(Program).Assembly, "docs/wiki/"));
});

The gateway sets the project name for you and syncs the host project the first time it is needed. You add no startup call.

In full Beacon:

var beacon = builder.Services.AddBeaconServices(builder.Configuration, o => { /* your options */ });
beacon.ExposeDocs(o =>
{
o.ProjectName = "Back Office"; // the project every Expose* call of this host uses
o.FromEmbeddedResources(typeof(Program).Assembly, "docs/wiki/");
// or o.FromDirectory("docs/wiki").Exclude("drafts/**");
});
beacon.UseSqlServer(); // ends the builder chain: call ExposeDocs before it
var app = builder.Build();
// ... apply migrations ...
await app.Services.SyncBeaconHostAsync(); // data sources first, then documents

SyncBeaconHostAsync is idempotent: a document whose content hash is unchanged is left alone, a changed one is updated and re-chunked, a removed file is archived. It is safe to run from several replicas at once.

4. Expose the data model (full Beacon only)

Section titled “4. Expose the data model (full Beacon only)”

Skip this step in the gateway: it has no data sources, so there is nothing for ExposeDbContext to attach to and no SQL tool to ground.

beacon.ExposeDbContext<ShopDbContext>(o =>
{
o.Name = "Shop";
o.ProjectName = "Back Office"; // the same project as ExposeDocs
o.ReadOnlyConnection("BeaconReadOnly") // ConnectionStrings:BeaconReadOnly, a read-only login
.AllowTables("Loan", "LoanInstallment", "Customer")
.ExcludeColumns(x => x.Table == "Customer" && x.Name.StartsWith("Kyc"))
.MaskColumns(x => x.Name is "SSN" or "AccountNumber");
});

Beacon reads the tables, columns, keys and foreign keys from the EF model without opening a connection, and takes descriptions from HasComment or, with GenerateDocumentationFile on, from your XML <summary> comments. Write those comments in business words: they become the column and table descriptions the agent reads. Columns whose names contain password, secret, token and similar words are excluded whatever you write. See Host DbContext for every option.

ToolWhat the agent gets from your material
searchDocuments as [IMPORTED_DOC] hits with their path and title, found by keyword, and by meaning when embeddings are enabled. Tables and columns too, in full Beacon.
get_documentationThe project-level answer ends with a list of your documents. document takes a path or an exact title and returns that document in full. datasource_name, table_name and schema_name narrow to the data model.
get_contextformat: "agents_md" returns a project brief: data sources, key tables, glossary terms, document titles and how to use the tools. Built from the catalog, with no LLM call.
ask (full Beacon)A conceptual question is answered from project documentation, including your documents; a data question is grounded in the schema, sample values, glossary and verified examples.
get_query_context (full Beacon)The same grounding context ask would use, so an agent can write its own SQL.

Documents work with no LLM and no embedder: keyword search matches title, path and chunk text. Embeddings, when configured, add meaning-based matching (Semantic retrieval).

6. Teach the vocabulary and verified answers (full Beacon only)

Section titled “6. Teach the vocabulary and verified answers (full Beacon only)”

Two kinds of grounding are curated by an Admin after the data source exists:

  • Business glossary: terms, synonyms and a metric expression, through /beacon/api/glossary (API only, no page). The top matches (GlossaryTopK, default 5) enter the prompt. See Business glossary.
  • Golden examples: human-verified question to SQL pairs. An Admin promotes an answer rated correct on the MCP Learning page (/beacon/mcp-learning, tab Golden candidates). The top matches (GoldenExemplarTopK, default 4) enter the prompt as authoritative. See Golden examples.

Both are scoped to the project, so another project that shares the data source never sees them.

  • Startup completes. In full Beacon SyncBeaconHostAsync ran after migrations.
  • GET /beacon/api/projects/{id}/imported-documents returns your documents (needs Read in the project).
  • Connect an MCP client (Connect Claude Code, Cursor or VS Code) and say this:
Say to Claude
Search the Back Office project for "active customer" and show me which documents match.
Then read the best match in full with get_documentation.
  • search answers with an [IMPORTED_DOC] line for your page, and get_documentation with document set to its path returns the text.
  • Full Beacon only: get_documentation with table_name returns the descriptions you wrote, and masked columns are flagged as masked.
  • Change one sentence in a document, redeploy, and the new text comes back from get_documentation.
SymptomCause and fix
No documents are listedThe sync has not run (full Beacon: call SyncBeaconHostAsync after migrations), the folder is wrong, or the glob matched nothing. A configured directory that does not exist fails startup.
Folder names look like _40_web or the path has dotsThe embedded resources have no LogicalName. Set it as in step 2.
A file is missing and the log has a size warningIt is over MaxDocumentBytes (512 KB). Split it.
Two files with names that differ only by case, one missingPaths compare ignoring case; the second is skipped with a warning naming its path. Rename one.
The project is called Back Office (host)A project that is not host-managed already had that name. The host project is created beside it. See The host project.
search finds nothing for a paraphraseEmbeddings are off, so matching is by keyword. Use the people’s own words in the document or enable embeddings.
A table is not visible to the agentIt is not in AllowTables / AllowEntity, or the caller cannot read the project.
A query on a host data source is refused for an unqualified tableHost data source SQL must be a single SELECT with schema-qualified table names, such as dbo.Customer.