Brand Governance MCP Server
FreeNot checkedFastMCP server exposing brand governance content and standards to MCP-compatible clients with API key authentication and tiered access control.
About
FastMCP server exposing brand governance content and standards to MCP-compatible clients with API key authentication and tiered access control.
README
Advanced Analytica Brand-First AI Governance Platform.
This repository contains a Python FastMCP server that exposes brand governance content to MCP-compatible clients such as Claude, ChatGPT, and custom agents. It validates client API keys, gates access by commercial layer, reads brand data from DigitalOcean Spaces, and returns structured JSON responses for every tool.
What Is BGML?
Brand Governance Markup Language (BGML) is the structured index and retrieval format this MCP uses to organize brand standards, related content collections, rules, metadata, and access-aware guidance.
What it does
- Validates API keys using SHA-256 key hashes stored in AWS S3.
- Serves Layer 1 brand content from Markdown and BGML indexes stored in DigitalOcean Spaces.
- Gates Layer 2 YAML sidecars and Layer 3 JSON tokens behind access flags.
- Surfaces standards, toolkits, asset-library, digital, and other indexed collections through MCP.
- Lists standards, content, rules, images, and trial status.
- Returns signed app-domain image URLs with seven-day expiry by default.
- Supports optional image manifests with structured metadata for governed asset selection.
- Provides a Layer 1
brand_answer_questiontool using indexed metadata and Markdown excerpts across permitted collections. - Runs locally or on DigitalOcean App Platform.
Code Structure
The MCP now separates retrieval behavior into a few focused code areas under src/:
src/prompts/: prompt and instruction helpers that control answer behavior, modes, and limitation textsrc/resources/: runtime content-loading helpers for Markdown, JSON sidecars, and future managed resourcessrc/schema/: semantic helpers for BGML interpretation such as applicability, contexts, and scopessrc/templates/: response-formatting helpers that turn structured data into client-facing outputsrc/workflows/: multi-step orchestration used for task-capable FastMCP workflows and future Inspector task runs
Use these directories for MCP application behavior and reusable loaders or formatters.
Do not store client asset files such as PowerPoint templates, InDesign packages, ZIP bundles, videos, or other binary brand resources in the application code tree. Those belong in DigitalOcean Spaces inside the client dataset, with the MCP code loading or describing them as needed.
Data contract
Each indexed content folder follows this pattern:
standards/logo/
page.md
page.yaml
page.json
images/
manifest.json
Image manifests are optional. When present, brand_get_image_list reads images/manifest.json and returns richer metadata for each asset. If a local manifest is missing, the MCP can also fall back to a parent master-image-manifest.json and use the matching entry for that content path.
Layer behavior:
| File | Layer | Purpose |
|---|---|---|
page.md |
1 | Narrative standard, examples, dos and donts |
page.yaml |
2 | Brando governance sidecar, precedence, validation and AI controls |
page.json |
3 | Compiled design-system tokens and API-ready objects |
images/ |
1+ | Reference assets and screenshots |
Image manifest schema
For governed image selection, images/manifest.json can define structured metadata for each asset:
{
"version": "1.0",
"standardId": "logo",
"assets": [
{
"filename": "logo-positive.png",
"title": "Colour positive logo",
"description": "Primary full-colour logo for white and light backgrounds.",
"section": "Approved variants",
"usage": "primary_logo",
"assetType": "logo_variant",
"variant": "full_lockup",
"colourway": "colour_positive",
"approvedBackgrounds": ["white", "light_gradient", "light_photography"],
"approvedUseCases": ["brand_identity", "corporate_communications"],
"restrictions": ["Do not use on dark backgrounds."],
"minSize": {
"digitalPx": 48,
"printInches": 0.375
},
"clearspaceRule": "Height of the lowercase c in the wordmark.",
"tags": ["logo", "primary", "positive"],
"priority": 1,
"role": "approved_variant"
}
]
}
Without a manifest, the MCP can still return filenames, paths, and image URLs, but it will not be able to make governed choices about variants, backgrounds, or use cases.
Image Metadata Generation
This repo also includes an admin script for generating starter images/manifest.json files from a standard folder:
python tools/generate_image_manifest.py \
--standard-dir /path/to/advanced-user/standards/grid-system \
--heuristic-only
For richer metadata, provide an OpenAI API key and let the script use OpenAI vision analysis against the page context and each image:
python tools/generate_image_manifest.py \
--standard-dir /path/to/advanced-user/standards/grid-system
The script writes images/manifest.json by default and produces entries shaped like:
{
"filename": "cq5dam.web.1280.1280.png",
"title": "Standard 12×12 page layout grid",
"description": "Reference image showing the PwC standard 12×12 grid for page layout, including margins and gutters.",
"section": "Standard grid",
"tags": ["grid-system", "page-layout", "12x12-grid", "margins", "gutters"],
"usage": "primary reference"
}
The BGML index can contain both:
bgml.standards: the core standards collectionbgml.collections: additional indexed groups such astoolkits,asset-library,digital,resources, and other brand content families
MCP tools
| Tool | Layer | Description |
|---|---|---|
brand_get_index |
1 | Return the BGML index for the client brand |
brand_list_standards |
1 | List available standards with summaries |
brand_get_standard |
1/2/3 | Fetch Markdown, YAML, or JSON for one standard, gated by tier |
brand_list_content |
1/2/3 | List indexed content across standards, toolkits, asset-library, digital, and other collections |
brand_get_content |
1/2/3 | Fetch Markdown, YAML, or JSON for one indexed content entry, gated by tier and capability |
brand_get_rules |
1 | Return indexed key rules for one standard |
brand_get_image_list |
1 | Return images for a standard as signed app-domain URLs with optional metadata |
brand_check_access |
1 | Return entitlement and expiry state |
brand_answer_question |
1 | Answer from BGML metadata and Markdown excerpts across permitted collections |
Future tools can be added for governed validation, conflict resolution, token export, and semantic search.
FastMCP Tasks And Workflows
Use normal MCP tools for direct request and response calls.
Use src/workflows/ when a feature becomes a multi-step operation that may later run as a FastMCP background task in Inspector. In this repo:
- tools are the public MCP surface
- workflows are the orchestration behind longer-running or progress-aware operations
- task runs are live executions of those workflows in FastMCP
brand_answer_question is wired so it can participate in FastMCP task execution when the fastmcp[tasks] runtime is installed. Standard synchronous calls still work the same way.
Quick start
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
python -m src.server
By default, the server expects AWS S3 credentials for key lookup and DigitalOcean Spaces credentials for brand data in .env.
Environment variables
AA_S3_ENDPOINT=https://brand-store.lon1.digitaloceanspaces.com
AA_S3_REGION=lon1
AA_S3_ACCESS_KEY=your_spaces_access_key
AA_S3_SECRET_KEY=your_spaces_secret_key
AA_KEYS_BUCKET=aa-keys
AA_KEYS_PROFILE=SchemaStreamCDNDeploy
AA_MCP_HOST=0.0.0.0
AA_MCP_PORT=8000
AA_MCP_PATH=/mcp/brand-governance
AA_MCP_TRANSPORT=http
AA_LOG_LEVEL=INFO
AA_PRESIGN_EXPIRY=604800
Key lookup model
The server does not store or look up raw keys. It hashes the key supplied by the client and loads the matching entitlement record from AWS S3:
aa-keys/
active/
sha256_<hash>.json
expired/
sha256_<hash>.json
clients/
pwc/
latest.json
A valid key file contains keyHash, not key.
Only API key files and their TTL/expiry state live in AWS S3. All brand data files, including the BGML index, Markdown pages, YAML sidecars, JSON tokens, and images, live in DigitalOcean Spaces.
The indexFile field may point at a Spaces object URL such as https://brand-store.lon1.digitaloceanspaces.com/brand-pwc/page-index.json.
{
"clientId": "pwc",
"clientName": "PricewaterhouseCoopers",
"keyHash": "sha256:...",
"keyHint": "...p5w4",
"tier": 1,
"created": "2026-05-04T09:00:00Z",
"expires": "2026-06-03T09:00:00Z",
"status": "active",
"mcpEndpoint": "https://advancedanalytica.co.uk/mcp/brand-governance",
"bucketUri": "s3://aa-brand-pwc-trial/",
"indexFile": "s3://aa-brand-pwc-trial/bgml-index.json",
"accessControl": {
"standards": true,
"toolkits": false,
"assetLibrary": false,
"yamlSidecars": false,
"jsonTokens": false,
"searchIntegration": false
},
"watermark": true,
"assetsRedacted": false
}
Creating a trial key
python tools/create_key.py \
--client-id pwc \
--client-name "PricewaterhouseCoopers" \
--bucket-uri s3://aa-brand-pwc-trial/ \
--index-file s3://aa-brand-pwc-trial/bgml-index.json \
--ttl 30
The script prints the raw key once and writes a key file containing only the hash.
Uploading a brand dataset
python tools/upload.py --brand-dir ./brands/pwc --client-id pwc --bucket aa-brand-pwc-trial
Running tests
pytest tests/
Tests use moto to mock AWS S3 for key lookup. They do not hit live AWS S3 or DigitalOcean Spaces.
Deploying to DigitalOcean App Platform
This repo includes an App Platform spec at .do/app.yaml for running the MCP as a small web service under:
/mcp/brand-governance
The intended shared app hostname is:
https://advancedanalytica.co.uk/mcp/brand-governance
Direct browser access to this route is expected to return an MCP protocol error such as 406 Not Acceptable or a session-related 400 response. Use an MCP client such as Claude Desktop or a FastMCP client for real tool calls.
The spec is sized for a small managed service:
instance_size_slug: basic-xxsinstance_count: 1- service route with
preserve_path_prefix: true
Before applying it to an existing app, set the run-time secrets in App Platform:
AA_KEYS_ACCESS_KEYAA_KEYS_SECRET_KEYAA_KEYS_SESSION_TOKENif your AWS credentials are temporaryDO_SPACES_KEYDO_SPACES_SECRET
Then update the existing app with doctl:
doctl apps update <app-id> --spec .do/app.yaml
If the existing app already has other components, merge the brand-governance-mcp service into that app's full spec rather than replacing the entire spec blindly.
For the current shared Advanced Analytica app, a merged full spec is included at:
That merged spec preserves:
- the existing
webstatic site - the existing
lead-apifunction mounted at/api - the new
brand-governance-mcpservice mounted at/mcp/brand-governance
Before applying the merged spec, replace:
- the MCP repo
repo_clone_urland branch if needed AA_KEYS_ACCESS_KEYAA_KEYS_SECRET_KEYAA_KEYS_SESSION_TOKENif requiredDO_SPACES_KEYDO_SPACES_SECRET
Apply it to the existing app:
doctl apps update be8a36e2-3af3-470c-b72a-7e567c73096f --spec .do/advancedanalytica-co-uk.merged.yaml
Connecting Claude Desktop
Add to ~/.claude/mcp.json:
{
"mcpServers": {
"brand-governance": {
"url": "https://advancedanalytica.co.uk/mcp/brand-governance",
"headers": {
"X-Brand-Key": "sk-brand-pwc-redacted"
}
}
}
}
MCP Inspector
To inspect the live UK Brand Governance MCP endpoint with MCP Inspector, set a live brand key in your local environment or .env:
BRAND_GOVERNANCE_API_KEY=sk-brand-pwc-redacted
Then launch the local helper script from the repo root:
bash tools/inspector_uk.sh
The script opens MCP Inspector against:
https://advancedanalytica.co.uk/mcp/brand-governance
and sends the key as the X-Brand-Key HTTP header.
The server also accepts connection-level Authorization: Bearer <key> auth for remote MCP clients that expose an API key field instead of custom headers.
Connecting OpenAI / ChatGPT
Use OpenAI's Responses API remote MCP configuration with a Streamable HTTP/SSE-compatible MCP endpoint. Pass the brand key through the remote MCP authorization/header configuration supported in your client environment.
Security rules
- Never store raw API keys server-side.
- Never expose one client's bucket to another client.
- Never return raw S3 errors to the client.
- Never expose YAML sidecars to Layer 1 keys.
- Never expose JSON tokens to Layer 1 or Layer 2 keys.
- Presigned image URLs expire after one hour by default.
- Trial keys and trial buckets can be removed using lifecycle policies.
License and IP
The Brando Schema, BGML format, and Brand-First AI Governance methodology are proprietary to Advanced Analytica unless explicitly published under a separate license.
Installing Brand Governance MCP Server
This server has no published package — it is built from source. Open the repository and follow its README.
▸ github.com/jonathanbowker/brand-governance-mcpFAQ
Is Brand Governance MCP Server MCP free?
Yes, Brand Governance MCP Server MCP is free — one-click install via Unyly at no cost.
Does Brand Governance MCP Server need an API key?
No, Brand Governance MCP Server runs without API keys or environment variables.
Is Brand Governance MCP Server hosted or self-hosted?
Self-hosted: the server runs locally on your machine via the install command above.
How do I install Brand Governance MCP Server in Claude Desktop, Claude Code or Cursor?
Open Brand Governance MCP Server on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.
Related MCPs
GitHub
PRs, issues, code search, CI status
by GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
by mcpdotdirectCompare Brand Governance MCP Server with
Not sure what to pick?
Find your stack in 60 seconds
Author?
Embed badge for your README
Browse similar
All development MCPs
