MCP
We are actively working to improve this documentation. The content you see here may be incomplete, subject to change, or may not fully reflect the current state of the feature. We appreciate your understanding as we continue to enhance our docs.
The Brightspot AI plugin can expose CMS content over the Model Context Protocol (MCP), letting external AI clients—IDE assistants, chat apps, custom agents—search, read, create, update, and delete content through a tool-calling interface.
The MCP server is a separate module that runs inside the Brightspot web application. It is implemented as an ApiEndpoint, so it inherits Brightspot's existing API client, credential, and permission model. The same @ToolMethod-annotated tools used by in-process agents (Ask AI, Create with AI) are reused as MCP tools.
How it works
- The
mcpmodule registers anApiEndpoint(McpApiEndpoint, display name MCP) that handles MCP protocol traffic at one or more configurable paths. - A servlet filter (
McpApiEndpointFilter) starts a stateless MCP server on application init. It discovers every concreteToolGroupon the classpath, resolves each@ToolMethod-annotated method into a tool, and registers it with the server. - The server advertises tools only—prompts and resources are disabled. Each tool name is namespaced as
<GroupName>_<methodName>(for example,Content_search). - Each incoming MCP request is authenticated against an
ApiClientrecord. Once validated, the request is delegated to the MCP transport servlet, which dispatches the tool call. - Tool return values become the MCP
structuredContentpayload. Scalars and collections are wrapped as{"result": ...}. Exceptions are returned as an error result with the stack trace as text content.
Installation
Add the mcp artifact alongside the core AI plugin:
- Maven
- Gradle
- Gradle (Kotlin DSL)
<dependency>
<groupId>com.brightspot.ai</groupId>
<artifactId>mcp</artifactId>
<version>3.0.0</version>
</dependency>
implementation 'com.brightspot.ai:mcp:3.0.0'
implementation("com.brightspot.ai:mcp:3.0.0")
This pulls in the upstream MCP SDK (io.modelcontextprotocol.sdk:mcp-core plus the Jackson JSON transport at runtime) and registers the MCP endpoint and built-in Content tool group.
Setting up the endpoint
The MCP server is exposed through a Brightspot API endpoint, configured in the CMS like any other endpoint.
To create an MCP endpoint:
- Click > Admin > APIs.
- Create a new API endpoint and select MCP as the type.
- In the Paths field, add one or more URL paths to serve MCP traffic at (for example,
/mcp). - Save.
The endpoint is now reachable at the configured paths on your application host. Point MCP clients at the full URL, including scheme and host.
Authentication
McpApiEndpoint accepts credentials from either of two headers, in order of precedence:
| Header | Format |
|---|---|
Authorization | Bearer <token> |
X-API-Key | <token> |
Tokens are validated against ApiClient records:
- Invalid credentials produce
401 Unauthorized. - Valid credentials that lack endpoint or permission access produce
403 Forbidden.
To issue credentials for an MCP client:
- Click > Admin > APIs.
- Create or open an API Client.
- Generate a token for the client and grant it access to the MCP endpoint.
- Configure access control under the MCP cluster on the same client (see Access control).
- Share the token with the MCP client out of band.
Access control
The McpApiClient modification adds two MCP-specific fields to every ApiClient, surfaced under the MCP cluster in the CMS:
- Allowed Sites — Sites this client can read from or write to. An empty set means unrestricted.
- Allowed Types — Content types this client can read or write. An empty set means unrestricted.
The built-in Content tool group enforces these restrictions on every call. Custom tool groups that operate on CMS content should consult McpApiClient and apply the same checks.
Treat MCP credentials like any other API token. A client with unrestricted allowed sites and types can read and modify any content the endpoint user can access.
Built-in tools
The mcp module ships one tool group, Content (ContentToolGroup), providing CRUD and search over Brightspot content. All tools are namespaced Content_*:
| Tool | Hints | Purpose |
|---|---|---|
Content_searchType | read-only, idempotent | Find content type names by partial match. |
Content_getType | read-only, idempotent | Get the JSON Schema for a content type. |
Content_getFieldValues | read-only, idempotent | List allowed values for a field with a value generator. |
Content_searchTextually | read-only, idempotent | Keyword search across content. |
Content_searchSemantically | read-only, idempotent | Embedding-based search across content. |
Content_get | read-only, idempotent | Fetch a single content item by ID. |
Content_generateIds | read-only | Generate fresh UUIDs for new content. |
Content_create | write | Create new content of a given type. |
Content_update | write | Update existing content by ID. |
Content_delete | write, destructive | Delete content by ID. |
The group also publishes a usage guide to the MCP server's instructions payload so that clients can route tool calls correctly without trial and error. See ContentToolGroup#getInstructions for the current text.
Content_searchSemantically requires a configured text embedding generator (see Configuration). The other tools work without one.
Adding custom tools
Any concrete subclass of ToolGroup on the classpath is picked up automatically. Tools defined this way are available both to the in-process agents and to MCP clients.
1@NullMarked2public class WeatherToolGroup extends ToolGroup {34@Override5public String getName() {6return "Weather";7}89@Override10public @Nullable String getInstructions() {11return "Use Weather_* tools for current conditions and forecasts.";12}1314@ToolMethod(15title = "Get the current temperature for a city",16readOnly = true,17destructive = false,18idempotent = false,19description = "Returns the current temperature in Celsius for the given city.")20public double currentTemperature(21@ToolParam(description = "City name, e.g. `San Francisco`.") String city) {2223return WeatherApi.lookup(city).temperatureCelsius();24}25}
Notes:
- The group's
getName()becomes the tool name prefix (Weather_currentTemperaturehere). - Per-method behavioral hints (
readOnly,destructive,idempotent) on@ToolMethodare forwarded to MCP clients, which may use them to auto-approve calls or prompt for confirmation. - Parameter schemas are derived from
@ToolParamannotations and the method signature. For non-standard schemas, supply aSchemaSuppliervia@ToolParam. - Return values are serialized as structured content. Scalars and collections are auto-wrapped as
{"result": ...}; return aMap<String, Object>for richer payloads. - Throwing from a tool method produces an MCP error result; the stack trace is included as text content.
For deeper internals—Tool, RunnableTool, ToolGroup discovery, and the agentic chat loop that consumes the same tools—see Architecture overview.