Run your own MCP server
Cortex ships a Model Context Protocol server so AI agents can read and write your knowledge graph — grounded in your ontology and gated by the same human review as any other write.
What you get
When the starter is on the classpath, an MCP server (built on Spring AI's MCP support) is
auto-configured and served over HTTP at /mcp. It is on by default; the single
switch cortex.mcp.enabled=false turns it off without excluding individual beans.
Configure the transport under Spring AI's own properties:
spring:
ai:
mcp:
server:
protocol: stateless
type: sync
instructions: Use this MCP for knowledge graph operations. Load cortex://ontology resource on connection
cortex:
mcp:
enabled: true # the default
Tools
Six tools. The read-only ones are marked idempotent; Ingest is the only writer, and even it does not touch the approved graph — it stages a branch for review.
| Tool | Parameter | What it does |
|---|---|---|
| Lint | ttl | Checks assertions against cortex://ontology: classes/properties not defined there are rejected; only rdf:type, rdfs:label, rdfs:comment are allowed beyond it. Returns the validated TTL, or the violations. Call before Ingest. Read-only. |
| Ingest | ttl | Lints, SHACL-validates against the approved assertions, trims already-known triples, and stages the rest on a new branch for human review. Returns the branch name (null if nothing was novel), or the errors. |
| Query | sparql | Runs a SPARQL SELECT (including inferred statements); returns a text table. Read-only. |
| Ask | sparql | Answers a SPARQL ASK — true/false. Read-only. |
| Describe | sparql | Runs a SPARQL DESCRIBE; returns Turtle. Read-only. |
| Search | text | Fuzzy full-text search over rdfs:label and rdfs:comment, tolerant of typos, ranked by relevance and by how often each resource is opened. Read-only. |
/branches/<branch> for a human once a
branch is returned.
The ontology resource
One MCP resource is exposed so agents can ground themselves before writing:
| Resource | URI | Media type |
|---|---|---|
| Ontology | cortex://ontology | text/turtle |
Connect a client
Point any MCP client at the HTTP endpoint. For example, a Claude Code .mcp.json:
{
"mcpServers": {
"cortex": { "type": "http", "url": "http://localhost:8080/mcp" }
}
}
A typical agent flow: read cortex://ontology → Search/Query
for existing resources → Lint the new Turtle → Ingest it →
a human approves the branch at /branches.
Customization
Bring your own schema
The graph is defined entirely by the resources you supply — override
cortex.ontologies, cortex.shapes, and cortex.rules (each a
list, merged in order) to model your own domain. Namespaces are yours; only
cortex:// is reserved. See Getting started.
Override any tool or resource
Every auto-configured bean is @ConditionalOnMissingBean, so declaring your own bean
of the same type replaces the default. Want to tighten the Ingest description, add a tool, or
swap the ontology resource? Define the bean and Cortex backs off:
@Configuration
class MyMcpCustomizations {
// Replaces the default QueryTools bean; add or restrict tools as you like.
@Bean
QueryTools queryTools(CortexQuery query, CortexSearch search) {
return new QueryTools(query, search);
}
}
Cortex extends nine role interfaces
(CortexQuery, CortexSearch, CortexIngestor, …). Injecting
the specific role instead of the whole Cortex keeps your beans focused and trivially
testable.
Turn off what you don't need
The MCP server, the web UI, backup, and restore are each a single switch — flip
cortex.web.enabled=false to run headless with just the MCP server, for instance.
See the Configuration reference.
Embed without Spring
Need the graph outside a Spring context — in a library, a test, or another framework? Use
CortexBuilder from cortex-core to assemble a Cortex
directly:
Cortex cortex = CortexBuilder.create()
.ontologies(List.of(ontologyTtl)) // file *content*, not paths
.shapes(List.of(shapesTtl))
.rules(List.of(rulesText))
.build(); // in-memory; .persistent(dir) for on-disk
The same eleven services the Spring auto-configuration wires are assembled here, so the two paths produce identical objects.