From dfd82e2206ad51e9dd6e705cdd4271e6fdce59ba Mon Sep 17 00:00:00 2001 From: Kerlenton Date: Fri, 24 Jul 2026 22:54:18 +0300 Subject: [PATCH 01/15] docs(blog): fix resultType value in 2026-07-28 RC post --- blog/content/posts/2026-05-21-mcp-2026-07-28-rc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blog/content/posts/2026-05-21-mcp-2026-07-28-rc.md b/blog/content/posts/2026-05-21-mcp-2026-07-28-rc.md index 5348f6861..fbc4686ba 100644 --- a/blog/content/posts/2026-05-21-mcp-2026-07-28-rc.md +++ b/blog/content/posts/2026-05-21-mcp-2026-07-28-rc.md @@ -145,7 +145,7 @@ change how those prompts are delivered. Instead of holding a Server-Sent Events ```json { - "resultType": "inputRequired", + "resultType": "input_required", "inputRequests": { "confirm": { "type": "elicitation", From 0f077dc1658a54c3469c657da1eed82fc97d0cdb Mon Sep 17 00:00:00 2001 From: John Haugabook Date: Fri, 24 Jul 2026 19:05:12 -0400 Subject: [PATCH 02/15] docs/authorization: resolve demo Python server 401 error --- .../docs/tutorials/security/authorization.mdx | 63 +++++++++++++++++-- 1 file changed, 58 insertions(+), 5 deletions(-) diff --git a/docs/docs/tutorials/security/authorization.mdx b/docs/docs/tutorials/security/authorization.mdx index 572d3e806..4f7adec02 100644 --- a/docs/docs/tutorials/security/authorization.mdx +++ b/docs/docs/tutorials/security/authorization.mdx @@ -648,8 +648,8 @@ class Config: AUTH_REALM: str = os.getenv("AUTH_REALM", "master") # OAuth client settings - OAUTH_CLIENT_ID: str = os.getenv("OAUTH_CLIENT_ID", "mcp-server") - OAUTH_CLIENT_SECRET: str = os.getenv("OAUTH_CLIENT_SECRET", "UO3rmozkFFkXr0QxPTkzZ0LMXDidIikB") + OAUTH_CLIENT_ID: str = os.getenv("OAUTH_CLIENT_ID", "test-client") + OAUTH_CLIENT_SECRET: str = os.getenv("OAUTH_CLIENT_SECRET", "") # Server settings MCP_SCOPE: str = os.getenv("MCP_SCOPE", "mcp:tools") @@ -869,8 +869,11 @@ class IntrospectionTokenVerifier(TokenVerifier): form_data = { "token": token, "client_id": self.client_id, - "client_secret": self.client_secret, } + # Only send client_secret when one is configured + # Public clients authenticate with client_id alone. + if self.client_secret: + form_data["client_secret"] = self.client_secret headers = {"Content-Type": "application/x-www-form-urlencoded"} response = await client.post( @@ -894,7 +897,13 @@ class IntrospectionTokenVerifier(TokenVerifier): client_id=data.get("client_id", "unknown"), scopes=data.get("scope", "").split() if data.get("scope") else [], expires_at=data.get("exp"), - resource=data.get("aud"), # Include resource in token + # AccessToken.resource is `str | None`. Keycloak returns `aud` + # as a *list* here (e.g. ["test-client", "http://localhost:3000", + # "account"]); passing that list straight in raises a pydantic + # ValidationError that the broad `except` below turns into a + # silent 401. We already confirmed this server's resource is a + # valid audience in `_validate_resource`, so record that. + resource=self.resource_url, ) except Exception as e: @@ -923,7 +932,51 @@ class IntrospectionTokenVerifier(TokenVerifier): return check_resource_allowed(self.resource_url, resource) ``` -For more details, see the [Python SDK documentation](https://github.com/modelcontextprotocol/python-sdk). +For more details, see below or the [Python SDK documentation](https://github.com/modelcontextprotocol/python-sdk). + +**Python MCP Server** + +In the server's root have a `pyproject.toml` file and a `mcp_server` folder. Put all the Python files in the `mcp_server` folder, and fill the `pyproject.toml` file like: + +```yaml +[project] +name = "mcp-simple-auth" +version = "0.1.0" +description = "A simple MCP server demonstrating OAuth authentication" +requires-python = ">=3.10" +authors = [{ name = "Model Context Protocol a Series of LF Projects, LLC." }] +license = { text = "MIT" } +dependencies = [ + "anyio>=4.5", + "click>=8.2.0", + "httpx>=0.27", + "mcp", + "pydantic>=2.0", + "pydantic-settings>=2.5.2", + "sse-starlette>=1.6.1", + "uvicorn>=0.23.1; sys_platform != 'emscripten'", +] + +[project.scripts] +mcp-simple-auth-rs = "mcp_server.server:main" + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] +packages = ["mcp_server"] + +[dependency-groups] +dev = ["pyright>=1.1.391", "pytest>=8.3.4", "ruff>=0.8.5"] +``` + +Then run the commands below to start the server. + +```bash +uv sync +uv run mcp-simple-auth-rs --port=3000 --auth-server=http://localhost:8080 --transport=streamable-http +``` From 091a265aba465a2cce59347df71b5052411b1dee Mon Sep 17 00:00:00 2001 From: John Haugabook Date: Fri, 24 Jul 2026 19:14:21 -0400 Subject: [PATCH 03/15] docs/authorization: resolve demo Python server 401 error --- docs/docs/tutorials/security/authorization.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/tutorials/security/authorization.mdx b/docs/docs/tutorials/security/authorization.mdx index 4f7adec02..6de531d04 100644 --- a/docs/docs/tutorials/security/authorization.mdx +++ b/docs/docs/tutorials/security/authorization.mdx @@ -938,7 +938,7 @@ For more details, see below or the [Python SDK documentation](https://github.com In the server's root have a `pyproject.toml` file and a `mcp_server` folder. Put all the Python files in the `mcp_server` folder, and fill the `pyproject.toml` file like: -```yaml +```toml [project] name = "mcp-simple-auth" version = "0.1.0" From 1bee97a5c062a6b522effc6e82cb01d10291b907 Mon Sep 17 00:00:00 2001 From: Liad Yosef Date: Sun, 26 Jul 2026 02:05:19 +0300 Subject: [PATCH 04/15] docs(community): add MCP Apps Working Group charter Adds the charter for the MCP Apps Working Group following the group charter template, and registers it in the docs navigation. The WG owns the MCP Apps extension (SEP-1865, Final), which defines predeclared UI resources under the ui:// scheme, tool-to-UI association via metadata, and bi-directional host/UI messaging over MCP's JSON-RPC base protocol. The specification and SDK live in the ext-apps repository. Scope, work items, and membership are grounded in the extension's live issues and the group's public rolling agenda, which has recorded tri-weekly meetings since 2025-12-17. --- docs/community/working-groups/mcp-apps.mdx | 183 +++++++++++++++++++++ docs/docs.json | 1 + 2 files changed, 184 insertions(+) create mode 100644 docs/community/working-groups/mcp-apps.mdx diff --git a/docs/community/working-groups/mcp-apps.mdx b/docs/community/working-groups/mcp-apps.mdx new file mode 100644 index 000000000..c1c53160c --- /dev/null +++ b/docs/community/working-groups/mcp-apps.mdx @@ -0,0 +1,183 @@ +--- +title: MCP Apps Charter +description: Charter for the MCP Apps Working Group. +--- + +## Group Type + +**Working Group** + +## Mission Statement + +The MCP Apps Working Group defines how MCP servers deliver interactive user +interfaces to hosts. The group emerged from the convergence of MCP-UI and the +OpenAI Apps SDK into a single open standard via +[SEP-1865](/seps/1865-mcp-apps-interactive-user-interfaces-for-mcp) +(Extensions Track, Final), which introduces predeclared UI resources (the +`ui://` URI scheme), tool-to-UI association through metadata, and +bi-directional host/UI communication over MCP's JSON-RPC base protocol. The WG +produces specification extensions, SDKs, reference implementations, and host +guidance because interactive UI touches the protocol spec, SDK surface, host +security model, and client rendering behavior across the ecosystem (Claude, +ChatGPT, VS Code, Goose, Postman, and others). + +## Scope + +### In Scope + +- **Specification Work**: The MCP Apps Extension + ([modelcontextprotocol/ext-apps](https://github.com/modelcontextprotocol/ext-apps)) + and related SEPs, including UI resource declaration, tool metadata, lifecycle + and messaging (`ui/*` methods and notifications), and content-type profiles + (initially `text/html;profile=mcp-app`) under the + `io.modelcontextprotocol/ui` namespace. +- **Future Content Types & Rendering Targets**: Non-HTML view mimetypes, + container-agnostic rendering, and declarative or generative UI directions, + including A2UI interoperability. +- **SDKs & Reference Implementations**: The MCP Apps SDK + (`@modelcontextprotocol/ext-apps`), example servers, the reference host, and + host integration references demonstrating secure rendering and + bi-directional communication. +- **Security Model**: Sandboxing, origin isolation, CSP guidance, auditability + of UI-initiated actions, and threat-model documentation for host + implementers. +- **Conformance**: Host compatibility tests, an official MCP App validator, and + the definition of what "spec-conformant" means for both apps and hosts. +- **Cross-Cutting Concerns**: Coordination with the Registry WG (app + discoverability and metadata), Agents WG (UI in agentic loops), Security IG + (sandboxing and UI-initiated tool calls), SDK WG and SDK maintainers + (per-language support), and external projects (A2UI, AG-UI, and community + frameworks). +- **Documentation**: Specification sections and guidance for app authors and + host implementers. + +### Out of Scope + +- **Host-specific design systems**: Hosts control final look-and-feel. The WG + standardizes the contract, not visual design. +- **Client implementation mandates**: We document rendering and security + patterns but cannot require specific host behavior beyond spec conformance. +- **General agent orchestration**: Agent loops and sub-agent coordination + belong to the Agents WG. This WG covers only the UI surface. +- **Core protocol changes**: Changes to base MCP semantics are proposed through + the [SEP process](/community/sep-guidelines) and owned by the relevant group + or Core Maintainers. This WG owns the Apps extension, not the base protocol. + +### Related Groups + +- **Agents WG**: interactive UI within agentic flows and task lifecycles. +- **[Registry WG](/community/working-groups/registry)**: app metadata, + discovery, and distribution. +- **[Security IG](/community/interest-groups/security)**: sandboxing model and + review of UI-initiated actions. +- **[SDK WG](/community/working-groups/sdk)**: per-language MCP Apps support + and SDK consistency. + +## Leadership + +| Role | Name | Organization | GitHub | Term | +| ---- | ----------- | ------------ | ------------------------------------ | ------- | +| Lead | Ido Salomon | MCP-UI | [@idosal](https://github.com/idosal) | Initial | +| Lead | Liad Yosef | MCP-UI / Ora | [@liady](https://github.com/liady) | Initial | + +## Authority & Decision Rights + +| Decision Type | Authority Level | +| ----------------------------------- | ------------------------------------------------------ | +| Meeting logistics & scheduling | WG Leads (autonomous) | +| Proposal prioritization within WG | WG Leads (autonomous) | +| SEP triage & closure (in scope) | WG Leads (autonomous, with documented rationale) | +| Technical design within scope | WG consensus | +| Spec changes (additive) | WG consensus → Core Maintainer approval | +| Spec changes (breaking/fundamental) | WG consensus → Core Maintainer approval + wider review | +| Scope expansion | Core Maintainer approval required | +| WG Member approval | WG Member sponsors | + +## Membership + +| Name | Organization | GitHub | Discord | Level | +| ------------------ | -------------------------- | ---------------------------------------------------------- | ------- | ----------- | +| Ido Salomon | MCP-UI | [@idosal](https://github.com/idosal) | | Lead | +| Liad Yosef | MCP-UI / Ora | [@liady](https://github.com/liady) | | Lead | +| Olivier Chafik | Anthropic / MCP Maintainer | [@ochafik](https://github.com/ochafik) | | WG Member | +| Jonathan Hefner | MCP Maintainer | [@jonathanhefner](https://github.com/jonathanhefner) | | WG Member | +| Anton Pidkuiko | MCP Maintainer | [@antonpk1](https://github.com/antonpk1) | | WG Member | +| Nick Cooper | OpenAI | [@nickcoai](https://github.com/nickcoai) | | WG Member | +| Max Stoiber | OpenAI | [@mstoiber-oai](https://github.com/mstoiber-oai) | | Participant | +| Dominic Farolino | Google / Chromium | [@domfarolino](https://github.com/domfarolino) | | Participant | +| Cameron Yick | Datadog | [@hydrosquall](https://github.com/hydrosquall) | | Participant | +| Frédéric Barthelet | Alpic | [@fredericbarthelet](https://github.com/fredericbarthelet) | | Participant | +| Ola Hungerford | Nordstrom | [@olaservo](https://github.com/olaservo) | | Participant | +| Yann Jouanin | | [@yannj-fr](https://github.com/yannj-fr) | | Participant | + +## Operations + +| Meeting | Frequency | Duration | Purpose | +| --------------- | -------------------------------- | -------- | ------------------------------------------------------------------------ | +| Working Session | Tri-weekly (Wednesday, 08:00 PT) | 60 min | Spec review, SDK coordination, host implementation feedback; open to all | +| Office Hours | Monthly (planned) | 30 min | Open Q&A for app authors, host implementers, and newcomers | + +Meetings are published at +[meet.modelcontextprotocol.io](https://meet.modelcontextprotocol.io) under the +`#mcp-apps-wg` tag. Agendas and notes are maintained as a public rolling +document, the +[MCP Apps Workgroup Agenda](https://docs.google.com/document/d/103S6IjN9D80ntbPIcK3mP_ZWdeFom2Mq8qpkpIsXRVI/edit), +and are posted per the MCP meeting policy. The group has met since +2025-12-17. + +Discord: `#mcp-apps-wg` + +## Resources + +- Extension specification & SDK: + [modelcontextprotocol/ext-apps](https://github.com/modelcontextprotocol/ext-apps) + (npm: `@modelcontextprotocol/ext-apps`) +- SEP: [SEP-1865](/seps/1865-mcp-apps-interactive-user-interfaces-for-mcp) +- Ecosystem docs: [MCP Apps overview](/extensions/apps/overview) and + [Build an MCP App](/extensions/apps/build) +- Documentation & API reference: + [apps.extensions.modelcontextprotocol.io](https://apps.extensions.modelcontextprotocol.io/) +- Issue tracker: + [ext-apps issues](https://github.com/modelcontextprotocol/ext-apps/issues) + +## Deliverables & Success Metrics + +### Active Work Items + +Live tracking is in +[ext-apps issues](https://github.com/modelcontextprotocol/ext-apps/issues) and +pull requests. Headline workstreams: + +| Item | Status | Target Date | Champion | +| ---------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ----------- | -------------------------------------------------------------------------------------- | +| Spec maintenance & next revision (current: 2026-01-26) | In Progress | | [@idosal](https://github.com/idosal), [@liady](https://github.com/liady) | +| MCP Apps SDK (`@modelcontextprotocol/ext-apps`, stable 1.x) | Maintained | | MCP Apps SDK maintainers | +| Host compatibility & conformance test suite ([#674](https://github.com/modelcontextprotocol/ext-apps/issues/674)) | In Progress | | [@idosal](https://github.com/idosal) | +| Reusable views & view session identity ([#430](https://github.com/modelcontextprotocol/ext-apps/issues/430)) | In Progress | | [@mstoiber-oai](https://github.com/mstoiber-oai), [@idosal](https://github.com/idosal) | +| Rendering architecture: decouple requirements from the double-sandboxed iframe ([#716](https://github.com/modelcontextprotocol/ext-apps/issues/716)) | In Review | | [@domfarolino](https://github.com/domfarolino) | +| Dynamic View Content via embedded resources ([#699](https://github.com/modelcontextprotocol/ext-apps/pull/699)) | Proposal | | [@liady](https://github.com/liady) | +| Views not tied to a specific tool call ([#672](https://github.com/modelcontextprotocol/ext-apps/issues/672)) | In Progress | | [@mstoiber-oai](https://github.com/mstoiber-oai), [@liady](https://github.com/liady) | +| Authoring toolkit: Agent Skills, reference host (`basic-host`), example suite | Maintained | | TBD | + +### Success Criteria + +- Published, stable extension specification (2026-01-26 revision shipped) with + a maintained SDK and reference host, and responsive triage of spec and SDK + issues. +- A conformance suite that host implementers can run, with results published so + app authors know what works where. +- Interoperable MCP Apps running unmodified across multiple major hosts, with + the documented security model adopted by those hosts. +- A clear, specified path for content types beyond HTML. +- MCP Apps established as the standard UI layer of the agentic web: a single + app implementation reaching every MCP host. + +## Changelog + +| Date | Change | +| ---------- | ------------------------------------------------------------------------------------------ | +| 2025-11-21 | SEP-1865 proposed; MCP-UI and OpenAI Apps SDK approaches unified under the MCP Apps banner | +| 2025-12-17 | First MCP Apps Working Group meeting | +| 2026-01-26 | MCP Apps extension specification revision 2026-01-26 published | +| 2026-01-28 | SEP-1865 marked Final and merged | +| 2026-07-26 | Initial charter | diff --git a/docs/docs.json b/docs/docs.json index 74bcb9caa..0360e197c 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -497,6 +497,7 @@ "community/working-groups/file-uploads", "community/working-groups/inspector-v2", "community/working-groups/interceptors", + "community/working-groups/mcp-apps", "community/working-groups/registry", "community/working-groups/sdk", "community/working-groups/server-card", From 465313b90a47d9d88da9a04a59236824085c2c0c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jul 2026 08:08:07 +0000 Subject: [PATCH 05/15] build(deps): bump actions/labeler from 6 to 7 Bumps [actions/labeler](https://github.com/actions/labeler) from 6 to 7. - [Release notes](https://github.com/actions/labeler/releases) - [Commits](https://github.com/actions/labeler/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/labeler dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/labeler.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index bfc7f07e5..1a1017092 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -11,6 +11,6 @@ jobs: label: runs-on: ubuntu-latest steps: - - uses: actions/labeler@v6 + - uses: actions/labeler@v7 with: sync-labels: false From b7c4ce4e15801856585974fd47e425b41952ab3e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jul 2026 09:53:00 +0000 Subject: [PATCH 06/15] build(deps-dev): bump typescript-eslint from 8.64.0 to 8.65.0 (#3136) Bumps [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) from 8.64.0 to 8.65.0. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.65.0/packages/typescript-eslint) --- updated-dependencies: - dependency-name: typescript-eslint dependency-version: 8.65.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 124 +++++++++++++++++++++++----------------------- package.json | 2 +- 2 files changed, 63 insertions(+), 63 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3d05de693..a2d851434 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,7 @@ "tsx": "^4.23.1", "typedoc": "^0.28.20", "typescript": "^6.0.3", - "typescript-eslint": "^8.64.0", + "typescript-eslint": "^8.65.0", "typescript-json-schema": "0.68.0", "unified": "^11.0.5" }, @@ -870,17 +870,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.64.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.64.0.tgz", - "integrity": "sha512-CGvQPBxN3wZLu6Rz2kFUpZeoCm78xUic92ck39KPePkO1NPOwjCqdQnm5Q87tpWw9vcBvW8XLrDXjH9PWYtJ3Q==", + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.65.0.tgz", + "integrity": "sha512-IEgob78X12rHpUmtcwFsXhZdVGJtwTVP8FiCLZkR6GlYVrl2PcuB+KhCE5BlVC/eQpQnu8WXRtkHZuPar+gCRA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.64.0", - "@typescript-eslint/type-utils": "8.64.0", - "@typescript-eslint/utils": "8.64.0", - "@typescript-eslint/visitor-keys": "8.64.0", + "@typescript-eslint/scope-manager": "8.65.0", + "@typescript-eslint/type-utils": "8.65.0", + "@typescript-eslint/utils": "8.65.0", + "@typescript-eslint/visitor-keys": "8.65.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" @@ -893,7 +893,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.64.0", + "@typescript-eslint/parser": "^8.65.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } @@ -909,16 +909,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.64.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.64.0.tgz", - "integrity": "sha512-KA0OshtlcCCXmbfqyZkM5pV3/WNraJf7DkJRLpyrmwPtud57H5BDX7C3k0LPSPxpprfRL+cJDGabF10mvNCoCw==", + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.65.0.tgz", + "integrity": "sha512-CZ4nMxWwgu1HEEFNkeaCptra9QCtkmKdgf3sWh1rl1trIhmxLilgTV4cwcbQ4wemnT4sWQN8CaKOmdYx+g2gMA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.64.0", - "@typescript-eslint/types": "8.64.0", - "@typescript-eslint/typescript-estree": "8.64.0", - "@typescript-eslint/visitor-keys": "8.64.0", + "@typescript-eslint/scope-manager": "8.65.0", + "@typescript-eslint/types": "8.65.0", + "@typescript-eslint/typescript-estree": "8.65.0", + "@typescript-eslint/visitor-keys": "8.65.0", "debug": "^4.4.3" }, "engines": { @@ -934,14 +934,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.64.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.64.0.tgz", - "integrity": "sha512-tk4WpOJ6IEbGrVHaNmM0YRrwAD3exZlIK3iadQNAxh4YKk6jvUQ4ecq18n+v7+meh+cJ3j+D8nbk8sRKhlwLQg==", + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.65.0.tgz", + "integrity": "sha512-SxnPhbTsGahizDgbu7oqFH/xVtzIqMd/s+WtnSxNxJZJpLbdT5IPdzg8EZxO3+PoKahXmwJLeNQOpKJb3/bi7Q==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.64.0", - "@typescript-eslint/types": "^8.64.0", + "@typescript-eslint/tsconfig-utils": "^8.65.0", + "@typescript-eslint/types": "^8.65.0", "debug": "^4.4.3" }, "engines": { @@ -956,14 +956,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.64.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.64.0.tgz", - "integrity": "sha512-CXEaFdYXjSTgKhisNkwCcJwTP8Pl+fmRrEQrri4nm3vU743bALrxzLmq7fHG/7e6a5xO0lDYeURpZmBuhHk54w==", + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.65.0.tgz", + "integrity": "sha512-Esbl8OSYiVxBokYgWPf7VVWg/BE798wXhimnn9ML9Pt5qoDf8bfQlgjlKXR/k98+AcNzlLKYrpCcrcuZ9DZLgg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.64.0", - "@typescript-eslint/visitor-keys": "8.64.0" + "@typescript-eslint/types": "8.65.0", + "@typescript-eslint/visitor-keys": "8.65.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -974,9 +974,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.64.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.64.0.tgz", - "integrity": "sha512-2yo8rRNKuzbVWQp5kslhANqZ2uDAeROQHBRZNPu8JDsHmeFNj/XJJhX/FhNUWmkHHvoNsKa6+tHJiig87EzsQw==", + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.65.0.tgz", + "integrity": "sha512-j6GzGqCiRdA7Qhur2VVmKZAkBLfnHFQfx4TaJGL9RMveZqCo48jSHHO0DTgizEnGhtWnqmbtCUSrqSkdiY/0Hg==", "dev": true, "license": "MIT", "engines": { @@ -991,15 +991,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.64.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.64.0.tgz", - "integrity": "sha512-XWG4Fmmv/6SvyS9nH8jWrKs6terwJvE8cyRt1CzYYqzp9OrPhCT4cMc/f7C6RZCwG+qMmiffJS1/qJP8G1URtg==", + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.65.0.tgz", + "integrity": "sha512-YjaZ7PRI5qY7ax2L3PbvX0rRyGtipAReCWs0mhhDBHjH/vl0g0BonaGXrKdKpMbIIsMIwDgbk/xzkBTyAltS5g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.64.0", - "@typescript-eslint/typescript-estree": "8.64.0", - "@typescript-eslint/utils": "8.64.0", + "@typescript-eslint/types": "8.65.0", + "@typescript-eslint/typescript-estree": "8.65.0", + "@typescript-eslint/utils": "8.65.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, @@ -1016,9 +1016,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.64.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.64.0.tgz", - "integrity": "sha512-qjhfuTfLXjA4IOzXvz0rTjT01BqEiIgPoUeMwiEjnaHKJMTNo8rH5pYW1a2L/0Dnux2fPC85AeyJoWaGa8WxTA==", + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.65.0.tgz", + "integrity": "sha512-JSSwWNy+H0E/01jJEM+hrX6N0OFDzFzeIhHFSAS01tlVaevpG8cFyYRPhS5yjGOvBUx3sqQHVMjCL1CAZZMxBg==", "dev": true, "license": "MIT", "engines": { @@ -1030,16 +1030,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.64.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.64.0.tgz", - "integrity": "sha512-Pztpsn1aCE1oWDvDEfUk31nngvvF7vUB5SwHFEaZIFpvw7WJtqUHHL4plBZDA9HfWJJjL13BdG0YrJInTUvoVA==", + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.65.0.tgz", + "integrity": "sha512-JboAE2swaYt4tb1fHhHTABE2K+OLy09XfcTbhnk4Pw96f9dd2e9iYsJ28gBggHlo5z5x1rkyWvcPoTuNTd4oGg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.64.0", - "@typescript-eslint/tsconfig-utils": "8.64.0", - "@typescript-eslint/types": "8.64.0", - "@typescript-eslint/visitor-keys": "8.64.0", + "@typescript-eslint/project-service": "8.65.0", + "@typescript-eslint/tsconfig-utils": "8.65.0", + "@typescript-eslint/types": "8.65.0", + "@typescript-eslint/visitor-keys": "8.65.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -1058,16 +1058,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.64.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.64.0.tgz", - "integrity": "sha512-aJUGVB3+U0htrrCjoA8qukw8cm8fNCGAxK/tVoS70k8aeb7DETKeFozRiVFIwEeN9WJLsjaP3ph8I60tY2XZoQ==", + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.65.0.tgz", + "integrity": "sha512-gXiwIHsYreboxeJucHKPvgwl7dXt50mF8s1/c00cP/WoVTyWKFdtfhRWwZiXYFU5H2O8vVoSLNrexFZjYS/SGA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.64.0", - "@typescript-eslint/types": "8.64.0", - "@typescript-eslint/typescript-estree": "8.64.0" + "@typescript-eslint/scope-manager": "8.65.0", + "@typescript-eslint/types": "8.65.0", + "@typescript-eslint/typescript-estree": "8.65.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1082,13 +1082,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.64.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.64.0.tgz", - "integrity": "sha512-mrtuL8Nsn6gi2H4mo5KMTp823M+3Q19Ew/i+Zlikq20tIMm99C3Ez0dCmkWWnxut20esQvTg8aUSEhMcAOXhEw==", + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.65.0.tgz", + "integrity": "sha512-8C71BQkGjiMmXtop7pHVJu1l2NNShFdkCyD6a2ezzs5vU/L3LRtb69EtcteFwz0mYMPzIgOw0n6OV4VBUWZd7A==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.64.0", + "@typescript-eslint/types": "8.65.0", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -3727,16 +3727,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.64.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.64.0.tgz", - "integrity": "sha512-0qg+pDNMnqYzqH9AnNK+39tejHvsShUOUUoRUgtnTGE7QuMZhiFDnozq8nHJVq+Wae6NMLKNWLg5WmkcC/ndyQ==", + "version": "8.65.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.65.0.tgz", + "integrity": "sha512-/ggrHAwyjENDusvyxbuqxAC2dTnZg/Z8F+fgQtYIz+L6n/9HfSlEZcFGV/NsMNa6CkGk0xUjUAFwC0vHOflvIA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.64.0", - "@typescript-eslint/parser": "8.64.0", - "@typescript-eslint/typescript-estree": "8.64.0", - "@typescript-eslint/utils": "8.64.0" + "@typescript-eslint/eslint-plugin": "8.65.0", + "@typescript-eslint/parser": "8.65.0", + "@typescript-eslint/typescript-estree": "8.65.0", + "@typescript-eslint/utils": "8.65.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" diff --git a/package.json b/package.json index 96aed177f..c2c2f3d8e 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "tsx": "^4.23.1", "typedoc": "^0.28.20", "typescript": "^6.0.3", - "typescript-eslint": "^8.64.0", + "typescript-eslint": "^8.65.0", "typescript-json-schema": "0.68.0", "unified": "^11.0.5" }, From 3b205e9b32a11289f40b28685ffaa4ec5b0533b6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jul 2026 09:54:05 +0000 Subject: [PATCH 07/15] build(deps-dev): bump postcss Bumps the npm_and_yarn group with 1 update in the /tools/sep-automation directory: [postcss](https://github.com/postcss/postcss). Updates `postcss` from 8.5.15 to 8.5.23 - [Release notes](https://github.com/postcss/postcss/releases) - [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/postcss/postcss/compare/8.5.15...8.5.23) --- updated-dependencies: - dependency-name: postcss dependency-version: 8.5.23 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] --- tools/sep-automation/package-lock.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/sep-automation/package-lock.json b/tools/sep-automation/package-lock.json index ba4ea8f72..6ce2d5132 100644 --- a/tools/sep-automation/package-lock.json +++ b/tools/sep-automation/package-lock.json @@ -2017,9 +2017,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.12", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", - "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", "dev": true, "funding": [ { @@ -2120,9 +2120,9 @@ "license": "MIT" }, "node_modules/postcss": { - "version": "8.5.15", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", - "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "version": "8.5.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.23.tgz", + "integrity": "sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==", "dev": true, "funding": [ { @@ -2140,7 +2140,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.12", + "nanoid": "^3.3.16", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, From 9d92d1517ee9e188cc8fb7600724b0f348593e08 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jul 2026 11:10:52 +0000 Subject: [PATCH 08/15] build(deps-dev): bump eslint from 10.7.0 to 10.8.0 (#3135) Bumps [eslint](https://github.com/eslint/eslint) from 10.7.0 to 10.8.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Commits](https://github.com/eslint/eslint/compare/v10.7.0...v10.8.0) --- updated-dependencies: - dependency-name: eslint dependency-version: 10.8.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 18 +++++++++--------- package.json | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index a2d851434..7a18416d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "ajv": "^8.20.0", "ajv-formats": "^3.0.1", "cheerio": "^1.2.0", - "eslint": "^10.7.0", + "eslint": "^10.8.0", "eslint-config-prettier": "^10.1.8", "glob": "^13.0.6", "prettier": "^3.9.5", @@ -543,9 +543,9 @@ } }, "node_modules/@eslint/config-helpers": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.6.0.tgz", - "integrity": "sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.7.0.tgz", + "integrity": "sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1649,9 +1649,9 @@ } }, "node_modules/eslint": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.7.0.tgz", - "integrity": "sha512-GVTD7s1vdIl6UYvAfriOPeY1Df8LIZjfofLvHwde+erDHGGuHyuM6xoxRxmHiebhYuD2p1vN4wWh0XzPARSGDQ==", + "version": "10.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.8.0.tgz", + "integrity": "sha512-nuKKvN+oIBO0koN7Tm7dlkmnkc21mtt0QJLwAKzjLq14y6lRTdVG36MZHJ8eQHwdJMwZbQNMlPOYedMq/oVJvQ==", "dev": true, "license": "MIT", "workspaces": [ @@ -1661,7 +1661,7 @@ "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", "@eslint/config-array": "^0.23.5", - "@eslint/config-helpers": "^0.6.0", + "@eslint/config-helpers": "^0.7.0", "@eslint/core": "^1.2.1", "@eslint/plugin-kit": "^0.7.2", "@humanfs/node": "^0.16.6", @@ -1685,7 +1685,7 @@ "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "minimatch": "^10.2.4", + "minimatch": "^10.2.5", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, diff --git a/package.json b/package.json index c2c2f3d8e..9b6ad6ad8 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "ajv": "^8.20.0", "ajv-formats": "^3.0.1", "cheerio": "^1.2.0", - "eslint": "^10.7.0", + "eslint": "^10.8.0", "eslint-config-prettier": "^10.1.8", "glob": "^13.0.6", "prettier": "^3.9.5", From 31eefec6b979b09ab2092490e2271c0eb38ccd38 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jul 2026 11:11:09 +0000 Subject: [PATCH 09/15] build(deps-dev): bump prettier from 3.9.5 to 3.9.6 (#3137) Bumps [prettier](https://github.com/prettier/prettier) from 3.9.5 to 3.9.6. - [Release notes](https://github.com/prettier/prettier/releases) - [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md) - [Commits](https://github.com/prettier/prettier/compare/3.9.5...3.9.6) --- updated-dependencies: - dependency-name: prettier dependency-version: 3.9.6 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7a18416d3..0bee3de3f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "eslint": "^10.8.0", "eslint-config-prettier": "^10.1.8", "glob": "^13.0.6", - "prettier": "^3.9.5", + "prettier": "^3.9.6", "remark-mdx": "^3.1.1", "remark-parse": "^11.0.0", "tsx": "^4.23.1", @@ -3392,9 +3392,9 @@ } }, "node_modules/prettier": { - "version": "3.9.5", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.5.tgz", - "integrity": "sha512-/FVl766LpUfB5vXgCYOYa0MeV/441Ia99AeICQIQFTY/Nw0roZwULcXpku5i1/m5kt/baz+s4Zogspd839HSMg==", + "version": "3.9.6", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.6.tgz", + "integrity": "sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==", "dev": true, "license": "MIT", "bin": { diff --git a/package.json b/package.json index 9b6ad6ad8..9f1943a36 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "eslint": "^10.8.0", "eslint-config-prettier": "^10.1.8", "glob": "^13.0.6", - "prettier": "^3.9.5", + "prettier": "^3.9.6", "remark-mdx": "^3.1.1", "remark-parse": "^11.0.0", "tsx": "^4.23.1", From 6e8bd2c94e9381e11e66414c33c124d742f89edd Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 27 Jul 2026 17:17:24 +0000 Subject: [PATCH 10/15] Add quotes shortcode for testimonial cards on the blog Adds a quotes/quote shortcode pair that renders testimonial cards in a row with hairline dividers, matching the docs site's design language. When more quotes than fit one view are given, a scroll-snap carousel with arrow buttons and pagination dots takes over. A lone quote renders full width as a pull quote. Includes a draft test post with fictional companies and original SVG wordmarks so the component can be reviewed in the PR preview. Drop the test post before or at merge. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01YWbYcGYDQESh3KWwpfoc4V --- blog/assets/css/extended/quotes.css | 177 ++++++++++++++++++ .../posts/quote-component-test/index.md | 85 +++++++++ .../quote-component-test/logo-copperfen.svg | 6 + .../quote-component-test/logo-harborlight.svg | 5 + .../quote-component-test/logo-lumenline.svg | 5 + .../quote-component-test/logo-quartzfield.svg | 4 + .../quote-component-test/logo-tidegate.svg | 5 + .../quote-component-test/logo-vexelworks.svg | 5 + blog/layouts/shortcodes/quote.html | 34 ++++ blog/layouts/shortcodes/quotes.html | 97 ++++++++++ 10 files changed, 423 insertions(+) create mode 100644 blog/assets/css/extended/quotes.css create mode 100644 blog/content/posts/quote-component-test/index.md create mode 100644 blog/content/posts/quote-component-test/logo-copperfen.svg create mode 100644 blog/content/posts/quote-component-test/logo-harborlight.svg create mode 100644 blog/content/posts/quote-component-test/logo-lumenline.svg create mode 100644 blog/content/posts/quote-component-test/logo-quartzfield.svg create mode 100644 blog/content/posts/quote-component-test/logo-tidegate.svg create mode 100644 blog/content/posts/quote-component-test/logo-vexelworks.svg create mode 100644 blog/layouts/shortcodes/quote.html create mode 100644 blog/layouts/shortcodes/quotes.html diff --git a/blog/assets/css/extended/quotes.css b/blog/assets/css/extended/quotes.css new file mode 100644 index 000000000..e25d8aa79 --- /dev/null +++ b/blog/assets/css/extended/quotes.css @@ -0,0 +1,177 @@ +/* ─── Quote cards (quotes / quote shortcodes) ────────────────────────────── */ +/* A row of testimonial cards separated by hairline dividers. The track is a + scroll-snap carousel; nav controls are injected by the shortcode's script + and stay hidden when everything fits one view. */ +.mcp-quotes { + margin: 40px 0; +} + +.mcp-quotes-track { + display: grid; + grid-auto-flow: column; + grid-auto-columns: 100%; + overflow-x: auto; + scroll-snap-type: x mandatory; + overscroll-behavior-x: contain; + scrollbar-width: none; +} + +.mcp-quotes-track::-webkit-scrollbar { + display: none; +} + +@media (min-width: 600px) { + .mcp-quotes-track { + grid-auto-columns: 50%; + } +} + +@media (min-width: 900px) { + .mcp-quotes-track { + grid-auto-columns: calc(100% / 3); + } +} + +.post-content .mcp-quote { + display: flex; + flex-direction: column; + min-width: 0; + margin: 0; + padding: 8px 24px; + border-inline-start: 1px solid var(--border); + scroll-snap-align: start; +} + +.post-content .mcp-quote:first-child { + padding-inline-start: 0; + border-inline-start: none; +} + +/* A lone quote reads as a pull quote: full track width, capped measure. */ +.mcp-quotes-track:has(> .mcp-quote:only-child) { + grid-auto-columns: 100%; +} + +.post-content .mcp-quote:only-child { + padding-inline-end: 0; +} + +.post-content .mcp-quote:only-child .mcp-quote-text { + max-width: 640px; +} + +@media (max-width: 599px) { + .post-content .mcp-quote { + padding-inline: 0 16px; + border-inline-start: none; + } +} + +/* Logos render at a common cap height regardless of the SVG's own aspect + ratio. Inline SVGs inherit currentColor so they track the theme. */ +.mcp-quote-logo { + display: block; + height: 28px; + margin-bottom: 20px; + color: var(--primary); +} + +.mcp-quote-logo svg, +.mcp-quote-logo img { + display: block; + height: 100%; + width: auto; + max-width: 100%; +} + +.mcp-quote-logo-text { + font-size: 18px; + font-weight: 600; + line-height: 28px; + letter-spacing: -0.01em; + color: var(--primary); +} + +/* Reset PaperMod's blockquote treatment (left bar, italic-ish inset). */ +.post-content .mcp-quote-text { + margin: 0; + padding: 0; + border: none; + font-size: 16px; + font-style: normal; + line-height: 1.6; + color: var(--content); +} + +.post-content .mcp-quote-text p { + display: inline; + margin: 0; + font-size: inherit; +} + +.post-content .mcp-quote-attrib { + margin-top: auto; + padding-top: 16px; + font-size: 14px; + color: var(--secondary); +} + +/* ─── Carousel controls ──────────────────────────────────────────────────── */ +.mcp-quotes-nav { + display: flex; + align-items: center; + justify-content: center; + gap: 16px; + margin-top: 28px; +} + +.mcp-quotes-nav[hidden] { + display: none; +} + +.mcp-quotes-btn { + display: inline-flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + padding: 0; + color: var(--primary); + background: var(--code-bg); + border: 1px solid var(--border); + border-radius: 50%; + cursor: pointer; + transition: border-color 0.15s ease; +} + +@media (hover: hover) { + .mcp-quotes-btn:not(:disabled):hover { + border-color: var(--primary); + } +} + +.mcp-quotes-btn:disabled { + opacity: 0.35; + cursor: default; +} + +.mcp-quotes-dots { + display: flex; + align-items: center; + gap: 8px; +} + +.mcp-quotes-dot { + width: 8px; + height: 8px; + padding: 0; + background: var(--tertiary); + border: none; + border-radius: 50%; + cursor: pointer; + transition: background 0.15s ease; +} + +.mcp-quotes-dot[aria-current="true"] { + background: var(--primary); +} diff --git a/blog/content/posts/quote-component-test/index.md b/blog/content/posts/quote-component-test/index.md new file mode 100644 index 000000000..ce061d4b1 --- /dev/null +++ b/blog/content/posts/quote-component-test/index.md @@ -0,0 +1,85 @@ +--- +title: "Quote Component Test" +date: "2026-07-27T12:00:00+00:00" +publishDate: "2026-07-27T12:00:00+00:00" +draft: true +slug: quote-component-test +description: "Test page for the quotes shortcode. All companies and people on this page are fictional." +author: + - The MCP project +tags: + - test +ShowToc: false +--- + +This page exercises the new `quotes` and `quote` shortcodes. Every company, +person, and quote below is fictional. Delete this post before or at merge. + +## Six quotes, carousel + +Six cards at three per view on desktop. The arrows and dots below the row +page through them. + +{{< quotes >}} +{{< quote name="Maren Odele" title="CTO" company="Lumenline" logo="logo-lumenline.svg" >}} +MCP let us wire our internal knowledge base into every agent we run. What used +to be a quarter of integration work shipped in a week. +{{< /quote >}} +{{< quote name="Priya Vanterpool" title="Head of Platform" company="Quartzfield Systems" logo="logo-quartzfield.svg" >}} +We replaced four bespoke plugin systems with one MCP server. Our team now +maintains a single surface instead of chasing SDK drift. +{{< /quote >}} +{{< quote name="Jonas Ferrick" title="VP of Engineering" company="Harborlight Analytics" logo="logo-harborlight.svg" >}} +Enterprise-managed authorization removed the consent-prompt wall for our +analysts. They log in once and every approved server is just there. +{{< /quote >}} +{{< quote name="Sana Whitlow" title="Principal Engineer" company="Vexelworks" logo="logo-vexelworks.svg" >}} +The spec is readable, the SDKs are boring in the best way, and conformance +tests caught our edge cases before customers did. +{{< /quote >}} +{{< quote name="Theo Marchbank" title="CPO" company="Copperfen Data" logo="logo-copperfen.svg" >}} +Our customers connect Copperfen to their agents themselves now. MCP turned an +enterprise sales blocker into a checkbox. +{{< /quote >}} +{{< quote name="Ines Kalvane" title="Director of AI" company="Tidegate Systems" logo="logo-tidegate.svg" >}} +Tool annotations gave our reviewers the context they needed to approve agent +access in days instead of months. +{{< /quote >}} +{{< /quotes >}} + +## Three quotes, static + +Three cards fit one view on desktop, so no carousel controls render. + +{{< quotes >}} +{{< quote name="Maren Odele" title="CTO" company="Lumenline" logo="logo-lumenline.svg" >}} +MCP let us wire our internal knowledge base into every agent we run. +{{< /quote >}} +{{< quote name="Priya Vanterpool" title="Head of Platform" company="Quartzfield Systems" logo="logo-quartzfield.svg" >}} +We replaced four bespoke plugin systems with one MCP server. +{{< /quote >}} +{{< quote name="Jonas Ferrick" title="VP of Engineering" company="Harborlight Analytics" logo="logo-harborlight.svg" >}} +Enterprise-managed authorization removed the consent-prompt wall for our +analysts. +{{< /quote >}} +{{< /quotes >}} + +## Single quote + +{{< quotes >}} +{{< quote name="Sana Whitlow" title="Principal Engineer" company="Vexelworks" logo="logo-vexelworks.svg" >}} +The spec is readable, the SDKs are boring in the best way, and conformance +tests caught our edge cases before customers did. We moved our whole tool +surface to MCP in one sprint and have not looked back. +{{< /quote >}} +{{< /quotes >}} + +## No logo fallback + +Without a `logo` param the company name renders as a text wordmark. + +{{< quotes >}} +{{< quote name="Theo Marchbank" title="CPO" company="Copperfen Data" >}} +Our customers connect Copperfen to their agents themselves now. +{{< /quote >}} +{{< /quotes >}} diff --git a/blog/content/posts/quote-component-test/logo-copperfen.svg b/blog/content/posts/quote-component-test/logo-copperfen.svg new file mode 100644 index 000000000..edee90c37 --- /dev/null +++ b/blog/content/posts/quote-component-test/logo-copperfen.svg @@ -0,0 +1,6 @@ + diff --git a/blog/content/posts/quote-component-test/logo-harborlight.svg b/blog/content/posts/quote-component-test/logo-harborlight.svg new file mode 100644 index 000000000..2a9327aa9 --- /dev/null +++ b/blog/content/posts/quote-component-test/logo-harborlight.svg @@ -0,0 +1,5 @@ + diff --git a/blog/content/posts/quote-component-test/logo-lumenline.svg b/blog/content/posts/quote-component-test/logo-lumenline.svg new file mode 100644 index 000000000..94211e8af --- /dev/null +++ b/blog/content/posts/quote-component-test/logo-lumenline.svg @@ -0,0 +1,5 @@ + diff --git a/blog/content/posts/quote-component-test/logo-quartzfield.svg b/blog/content/posts/quote-component-test/logo-quartzfield.svg new file mode 100644 index 000000000..83edee480 --- /dev/null +++ b/blog/content/posts/quote-component-test/logo-quartzfield.svg @@ -0,0 +1,4 @@ + diff --git a/blog/content/posts/quote-component-test/logo-tidegate.svg b/blog/content/posts/quote-component-test/logo-tidegate.svg new file mode 100644 index 000000000..27d962cf4 --- /dev/null +++ b/blog/content/posts/quote-component-test/logo-tidegate.svg @@ -0,0 +1,5 @@ + diff --git a/blog/content/posts/quote-component-test/logo-vexelworks.svg b/blog/content/posts/quote-component-test/logo-vexelworks.svg new file mode 100644 index 000000000..0d0d891a8 --- /dev/null +++ b/blog/content/posts/quote-component-test/logo-vexelworks.svg @@ -0,0 +1,5 @@ + diff --git a/blog/layouts/shortcodes/quote.html b/blog/layouts/shortcodes/quote.html new file mode 100644 index 000000000..67db1279a --- /dev/null +++ b/blog/layouts/shortcodes/quote.html @@ -0,0 +1,34 @@ +{{- /* + A single testimonial card. Use inside a `quotes` block. + + Params: + name - person's name + title - person's role, shown after the name + company - company name, used as the logo's accessible label + (and shown as text when no logo is given) + logo - filename of an SVG in the post's page bundle, or a static path. + Bundle SVGs are inlined so currentColor tracks the theme. + + The quote text goes in the shortcode body. Markdown is supported. +*/ -}} +{{- $name := .Get "name" -}} +{{- $title := .Get "title" -}} +{{- $company := .Get "company" -}} +{{- $logo := .Get "logo" -}} +
+ {{- with $logo -}} + {{- with $.Page.Resources.GetMatch . -}} + {{- if eq .MediaType.SubType "svg" -}} + + {{- else -}} + + {{- end -}} + {{- else -}} + + {{- end -}} + {{- else -}} + + {{- end }} +
“{{ trim .Inner " \n" | .Page.RenderString }}”
+
{{ $name }}{{ with $title }}, {{ . }}{{ end }}
+
diff --git a/blog/layouts/shortcodes/quotes.html b/blog/layouts/shortcodes/quotes.html new file mode 100644 index 000000000..2f44ad489 --- /dev/null +++ b/blog/layouts/shortcodes/quotes.html @@ -0,0 +1,97 @@ +{{- /* + Testimonial quote row. Wraps one or more inner `quote` shortcodes in a + scroll-snap carousel. Nav controls stay hidden unless the quotes overflow + one view, so 1-3 quotes render as a plain static row. + + Usage: + {{< quotes >}} + {{< quote name="Ada Person" title="CTO" company="Acme" logo="acme.svg" >}} + Quote text, markdown allowed. + {{< /quote >}} + {{< /quotes >}} +*/ -}} +{{- $label := .Get "label" | default "Testimonials" -}} +
+
+ {{ .Inner }} +
+ +
+{{- if not (.Page.Store.Get "mcp-quotes-js") -}} +{{- .Page.Store.Set "mcp-quotes-js" true }} + +{{- end -}} From 118388dc3446e00a8aa28e6b8745a62d9dc18aff Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 27 Jul 2026 17:50:59 +0000 Subject: [PATCH 11/15] Align quote attributions to a shared start line Cards in a quotes row now adopt the track's explicit logo, quote, and attribution rows via CSS subgrid, so every attribution starts at the same line across a row and across carousel pages. Long quotes spill downward without clamping and short cards keep the open space. Attributions that wrap do so below the shared line. Browsers without subgrid fall back to the previous bottom-aligned flex layout. Subgrid is skipped below 600px where cards render one per view. Test post quotes now vary in length to show the behavior. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01YWbYcGYDQESh3KWwpfoc4V --- blog/assets/css/extended/quotes.css | 27 +++++++++++++++++++ .../posts/quote-component-test/index.md | 24 ++++++++++++----- 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/blog/assets/css/extended/quotes.css b/blog/assets/css/extended/quotes.css index e25d8aa79..dff9b8b44 100644 --- a/blog/assets/css/extended/quotes.css +++ b/blog/assets/css/extended/quotes.css @@ -116,6 +116,33 @@ color: var(--secondary); } +/* Attributions start on the same line in every card. The track exposes three + explicit rows (logo / quote / attribution) and each card adopts them via + subgrid, so the quote row is sized by the longest quote in the set and + every attribution starts at the same y, on every carousel page. Long + quotes spill downward inside that row; short cards keep the open space. + Browsers without subgrid keep the flex column above, where attributions + bottom-align instead. Skipped under 600px, where cards show one per view + and cross-card alignment would only add empty space. */ +@media (min-width: 600px) { + @supports (grid-template-rows: subgrid) { + .mcp-quotes-track { + grid-template-rows: auto auto auto; + } + + .post-content .mcp-quote { + display: grid; + grid-template-rows: subgrid; + grid-row: span 3; + } + + .post-content .mcp-quote .mcp-quote-attrib { + margin-top: 0; + align-self: start; + } + } +} + /* ─── Carousel controls ──────────────────────────────────────────────────── */ .mcp-quotes-nav { display: flex; diff --git a/blog/content/posts/quote-component-test/index.md b/blog/content/posts/quote-component-test/index.md index ce061d4b1..54c3708da 100644 --- a/blog/content/posts/quote-component-test/index.md +++ b/blog/content/posts/quote-component-test/index.md @@ -18,12 +18,17 @@ person, and quote below is fictional. Delete this post before or at merge. ## Six quotes, carousel Six cards at three per view on desktop. The arrows and dots below the row -page through them. +page through them. Quote lengths differ on purpose: long quotes spill +downward and every attribution starts on the same line. {{< quotes >}} {{< quote name="Maren Odele" title="CTO" company="Lumenline" logo="logo-lumenline.svg" >}} MCP let us wire our internal knowledge base into every agent we run. What used -to be a quarter of integration work shipped in a week. +to be a quarter of integration work shipped in a week. Since then we have +connected our ticketing system, our data warehouse, and two internal CLIs +through the same server. Every new tool we expose is available to every agent +on day one, and the protocol absorbed client version skew far better than our +old plugin system ever did. {{< /quote >}} {{< quote name="Priya Vanterpool" title="Head of Platform" company="Quartzfield Systems" logo="logo-quartzfield.svg" >}} We replaced four bespoke plugin systems with one MCP server. Our team now @@ -35,7 +40,10 @@ analysts. They log in once and every approved server is just there. {{< /quote >}} {{< quote name="Sana Whitlow" title="Principal Engineer" company="Vexelworks" logo="logo-vexelworks.svg" >}} The spec is readable, the SDKs are boring in the best way, and conformance -tests caught our edge cases before customers did. +tests caught our edge cases before customers did. We moved our whole tool +surface to MCP in one sprint. The part that surprised me was how little glue +code survived the migration. We deleted more adapter code than we wrote, and +the server we shipped has needed exactly one patch since launch. {{< /quote >}} {{< quote name="Theo Marchbank" title="CPO" company="Copperfen Data" logo="logo-copperfen.svg" >}} Our customers connect Copperfen to their agents themselves now. MCP turned an @@ -43,20 +51,24 @@ enterprise sales blocker into a checkbox. {{< /quote >}} {{< quote name="Ines Kalvane" title="Director of AI" company="Tidegate Systems" logo="logo-tidegate.svg" >}} Tool annotations gave our reviewers the context they needed to approve agent -access in days instead of months. +access in days instead of months. Our security team reads the annotations +directly during review, and that alone cut two meetings out of every rollout. {{< /quote >}} {{< /quotes >}} ## Three quotes, static -Three cards fit one view on desktop, so no carousel controls render. +Three cards fit one view on desktop, so no carousel controls render. The +middle quote runs longer to show the shared attribution line in a static row. {{< quotes >}} {{< quote name="Maren Odele" title="CTO" company="Lumenline" logo="logo-lumenline.svg" >}} MCP let us wire our internal knowledge base into every agent we run. {{< /quote >}} {{< quote name="Priya Vanterpool" title="Head of Platform" company="Quartzfield Systems" logo="logo-quartzfield.svg" >}} -We replaced four bespoke plugin systems with one MCP server. +We replaced four bespoke plugin systems with one MCP server. Our team now +maintains a single surface instead of chasing SDK drift, and onboarding a new +integration went from a two week project to an afternoon. {{< /quote >}} {{< quote name="Jonas Ferrick" title="VP of Engineering" company="Harborlight Analytics" logo="logo-harborlight.svg" >}} Enterprise-managed authorization removed the consent-prompt wall for our From ae681e27134227706654fb9a57f29becc997dce0 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 27 Jul 2026 18:08:04 +0000 Subject: [PATCH 12/15] Break the quote strip out of the prose column The quotes row now bleeds horizontally past the post column, capped at 1200px and centered in the viewport, with a slice of the next card peeking at the right edge whenever more cards exist than fit one view. The bleed bound leaves a 32px gutter that absorbs the page scrollbar, so the page never scrolls horizontally. Carousel init now waits for DOMContentLoaded so every quotes block on a page gets its controls, and the arrow disabled state follows the actual scroll position. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01YWbYcGYDQESh3KWwpfoc4V --- blog/assets/css/extended/quotes.css | 41 ++++++++++++++++++++++++++--- blog/layouts/shortcodes/quotes.html | 16 ++++++++--- 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/blog/assets/css/extended/quotes.css b/blog/assets/css/extended/quotes.css index dff9b8b44..e20bce78f 100644 --- a/blog/assets/css/extended/quotes.css +++ b/blog/assets/css/extended/quotes.css @@ -2,8 +2,22 @@ /* A row of testimonial cards separated by hairline dividers. The track is a scroll-snap carousel; nav controls are injected by the shortcode's script and stay hidden when everything fits one view. */ + +/* The strip breaks out of the prose column: symmetric negative margins grow + it toward the viewport edges, capped at 1200px so it stays sane on wide + monitors. The viewport bound is 50vw - 50% - 32px per side. 100vw includes + the page scrollbar, so the 32px gutter both absorbs the scrollbar width + and keeps a visible margin, which is what prevents a page-level horizontal + scrollbar. The prose column is centered in the viewport, so symmetric + margins keep the strip centered too. */ .mcp-quotes { - margin: 40px 0; + --mcp-quotes-bleed: max(0px, min((1200px - 100%) / 2, 50vw - 50% - 32px)); + margin: 40px calc(-1 * var(--mcp-quotes-bleed)); +} + +/* A lone quote is a pull quote, not a strip: it stays in the prose column. */ +.mcp-quotes:has(.mcp-quote:only-child) { + --mcp-quotes-bleed: 0px; } .mcp-quotes-track { @@ -20,16 +34,36 @@ display: none; } +/* When more cards exist than fit one view, they are sized a bit narrower so + a slice of the next card peeks at the right edge, signaling that the strip + scrolls. Sets that fit exactly (1, 2, or 3 cards per breakpoint) keep the + full division and no peek. */ +@media (max-width: 599px) { + .mcp-quotes-track:has(> .mcp-quote + .mcp-quote) { + grid-auto-columns: calc(100% - 44px); + } +} + @media (min-width: 600px) { .mcp-quotes-track { grid-auto-columns: 50%; } } +@media (min-width: 600px) and (max-width: 899px) { + .mcp-quotes-track:has(> .mcp-quote:nth-child(3)) { + grid-auto-columns: calc((100% - 56px) / 2); + } +} + @media (min-width: 900px) { .mcp-quotes-track { grid-auto-columns: calc(100% / 3); } + + .mcp-quotes-track:has(> .mcp-quote:nth-child(4)) { + grid-auto-columns: calc((100% - 72px) / 3); + } } .post-content .mcp-quote { @@ -60,10 +94,11 @@ max-width: 640px; } +/* 1-up mobile: tighter padding, but keep the hairline so the peeking next + card reads as a separate card. */ @media (max-width: 599px) { .post-content .mcp-quote { - padding-inline: 0 16px; - border-inline-start: none; + padding-inline: 16px; } } diff --git a/blog/layouts/shortcodes/quotes.html b/blog/layouts/shortcodes/quotes.html index 2f44ad489..76920767b 100644 --- a/blog/layouts/shortcodes/quotes.html +++ b/blog/layouts/shortcodes/quotes.html @@ -60,8 +60,9 @@ function update() { var i = current(); - prev.disabled = i <= 0; - next.disabled = i >= pageCount() - 1; + var max = track.scrollWidth - track.clientWidth; + prev.disabled = track.scrollLeft <= 2; + next.disabled = track.scrollLeft >= max - 2; dots.forEach(function (dot, j) { dot.setAttribute("aria-current", j === i ? "true" : "false"); }); @@ -91,7 +92,16 @@ build(); } - document.querySelectorAll(".mcp-quotes").forEach(init); + /* This script is emitted with the first quotes block, before later + blocks on the page exist, so wait for the full DOM. */ + function initAll() { + document.querySelectorAll(".mcp-quotes").forEach(init); + } + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", initAll); + } else { + initAll(); + } })(); {{- end -}} From d07b58f86455c7d380496a8893b7bb9a070806ef Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 27 Jul 2026 21:57:48 +0000 Subject: [PATCH 13/15] Set quote attribution and text-logo fallback to regular weight PaperMod bolds figure > figcaption, which made the Name, Title line read too heavy. Override it to font-weight 400 so the attribution is a quiet secondary line, and drop the 600 weight on the no-logo company name fallback to match. --- blog/assets/css/extended/quotes.css | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/blog/assets/css/extended/quotes.css b/blog/assets/css/extended/quotes.css index e20bce78f..c63a08324 100644 --- a/blog/assets/css/extended/quotes.css +++ b/blog/assets/css/extended/quotes.css @@ -121,7 +121,7 @@ .mcp-quote-logo-text { font-size: 18px; - font-weight: 600; + font-weight: 400; line-height: 28px; letter-spacing: -0.01em; color: var(--primary); @@ -144,10 +144,13 @@ font-size: inherit; } +/* PaperMod bolds figure > figcaption; the attribution is a quiet secondary + line ("Name, Title"), so reset it to regular weight. */ .post-content .mcp-quote-attrib { margin-top: auto; padding-top: 16px; font-size: 14px; + font-weight: 400; color: var(--secondary); } From 560d843035c48071db511ff3804910c149d89292 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 27 Jul 2026 22:06:36 +0000 Subject: [PATCH 14/15] Bold the attribution name and move the title to its own line The figcaption now renders the name and title as separate block spans instead of one "Name, Title" line. The name is 700 in the body text color, the title stays 400 in the muted secondary color. A quote with no title renders the name alone. The test post gains a no-title variant to exercise that path. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01YWbYcGYDQESh3KWwpfoc4V --- blog/assets/css/extended/quotes.css | 18 ++++++++++++++++-- .../posts/quote-component-test/index.md | 12 ++++++++++++ blog/layouts/shortcodes/quote.html | 9 +++++++-- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/blog/assets/css/extended/quotes.css b/blog/assets/css/extended/quotes.css index c63a08324..f081b9fb8 100644 --- a/blog/assets/css/extended/quotes.css +++ b/blog/assets/css/extended/quotes.css @@ -144,16 +144,30 @@ font-size: inherit; } -/* PaperMod bolds figure > figcaption; the attribution is a quiet secondary - line ("Name, Title"), so reset it to regular weight. */ +/* Attribution: the name bold on one line, the title regular and muted on the + next. PaperMod bolds figure > figcaption wholesale, so the figcaption is + reset to 400 and only the name span re-bolds (700, matching the blog's + strong text). Both lines share one tight line-height so the pair reads as + a unit, not two paragraphs. */ .post-content .mcp-quote-attrib { margin-top: auto; padding-top: 16px; font-size: 14px; font-weight: 400; + line-height: 1.45; color: var(--secondary); } +.mcp-quote-attrib-name { + display: block; + font-weight: 700; + color: var(--content); +} + +.mcp-quote-attrib-title { + display: block; +} + /* Attributions start on the same line in every card. The track exposes three explicit rows (logo / quote / attribution) and each card adopts them via subgrid, so the quote row is sized by the longest quote in the set and diff --git a/blog/content/posts/quote-component-test/index.md b/blog/content/posts/quote-component-test/index.md index 54c3708da..a1f340a99 100644 --- a/blog/content/posts/quote-component-test/index.md +++ b/blog/content/posts/quote-component-test/index.md @@ -95,3 +95,15 @@ Without a `logo` param the company name renders as a text wordmark. Our customers connect Copperfen to their agents themselves now. {{< /quote >}} {{< /quotes >}} + +## No title + +Without a `title` param the attribution is the name alone, no empty second +line. + +{{< quotes >}} +{{< quote name="Ines Kalvane" company="Tidegate Systems" logo="logo-tidegate.svg" >}} +Tool annotations gave our reviewers the context they needed to approve agent +access in days instead of months. +{{< /quote >}} +{{< /quotes >}} diff --git a/blog/layouts/shortcodes/quote.html b/blog/layouts/shortcodes/quote.html index 67db1279a..c2516bd29 100644 --- a/blog/layouts/shortcodes/quote.html +++ b/blog/layouts/shortcodes/quote.html @@ -3,7 +3,7 @@ Params: name - person's name - title - person's role, shown after the name + title - person's role, shown on its own line under the name company - company name, used as the logo's accessible label (and shown as text when no logo is given) logo - filename of an SVG in the post's page bundle, or a static path. @@ -30,5 +30,10 @@ {{- end }}
“{{ trim .Inner " \n" | .Page.RenderString }}”
-
{{ $name }}{{ with $title }}, {{ . }}{{ end }}
+
+ {{ $name }} + {{- with $title }} + {{ . }} + {{- end }} +
From 4549a6aa9334db544e64136fc090a4e9782a2fd3 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 27 Jul 2026 22:13:48 +0000 Subject: [PATCH 15/15] Remove quote component test post Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01YWbYcGYDQESh3KWwpfoc4V --- .../posts/quote-component-test/index.md | 109 ------------------ .../quote-component-test/logo-copperfen.svg | 6 - .../quote-component-test/logo-harborlight.svg | 5 - .../quote-component-test/logo-lumenline.svg | 5 - .../quote-component-test/logo-quartzfield.svg | 4 - .../quote-component-test/logo-tidegate.svg | 5 - .../quote-component-test/logo-vexelworks.svg | 5 - 7 files changed, 139 deletions(-) delete mode 100644 blog/content/posts/quote-component-test/index.md delete mode 100644 blog/content/posts/quote-component-test/logo-copperfen.svg delete mode 100644 blog/content/posts/quote-component-test/logo-harborlight.svg delete mode 100644 blog/content/posts/quote-component-test/logo-lumenline.svg delete mode 100644 blog/content/posts/quote-component-test/logo-quartzfield.svg delete mode 100644 blog/content/posts/quote-component-test/logo-tidegate.svg delete mode 100644 blog/content/posts/quote-component-test/logo-vexelworks.svg diff --git a/blog/content/posts/quote-component-test/index.md b/blog/content/posts/quote-component-test/index.md deleted file mode 100644 index a1f340a99..000000000 --- a/blog/content/posts/quote-component-test/index.md +++ /dev/null @@ -1,109 +0,0 @@ ---- -title: "Quote Component Test" -date: "2026-07-27T12:00:00+00:00" -publishDate: "2026-07-27T12:00:00+00:00" -draft: true -slug: quote-component-test -description: "Test page for the quotes shortcode. All companies and people on this page are fictional." -author: - - The MCP project -tags: - - test -ShowToc: false ---- - -This page exercises the new `quotes` and `quote` shortcodes. Every company, -person, and quote below is fictional. Delete this post before or at merge. - -## Six quotes, carousel - -Six cards at three per view on desktop. The arrows and dots below the row -page through them. Quote lengths differ on purpose: long quotes spill -downward and every attribution starts on the same line. - -{{< quotes >}} -{{< quote name="Maren Odele" title="CTO" company="Lumenline" logo="logo-lumenline.svg" >}} -MCP let us wire our internal knowledge base into every agent we run. What used -to be a quarter of integration work shipped in a week. Since then we have -connected our ticketing system, our data warehouse, and two internal CLIs -through the same server. Every new tool we expose is available to every agent -on day one, and the protocol absorbed client version skew far better than our -old plugin system ever did. -{{< /quote >}} -{{< quote name="Priya Vanterpool" title="Head of Platform" company="Quartzfield Systems" logo="logo-quartzfield.svg" >}} -We replaced four bespoke plugin systems with one MCP server. Our team now -maintains a single surface instead of chasing SDK drift. -{{< /quote >}} -{{< quote name="Jonas Ferrick" title="VP of Engineering" company="Harborlight Analytics" logo="logo-harborlight.svg" >}} -Enterprise-managed authorization removed the consent-prompt wall for our -analysts. They log in once and every approved server is just there. -{{< /quote >}} -{{< quote name="Sana Whitlow" title="Principal Engineer" company="Vexelworks" logo="logo-vexelworks.svg" >}} -The spec is readable, the SDKs are boring in the best way, and conformance -tests caught our edge cases before customers did. We moved our whole tool -surface to MCP in one sprint. The part that surprised me was how little glue -code survived the migration. We deleted more adapter code than we wrote, and -the server we shipped has needed exactly one patch since launch. -{{< /quote >}} -{{< quote name="Theo Marchbank" title="CPO" company="Copperfen Data" logo="logo-copperfen.svg" >}} -Our customers connect Copperfen to their agents themselves now. MCP turned an -enterprise sales blocker into a checkbox. -{{< /quote >}} -{{< quote name="Ines Kalvane" title="Director of AI" company="Tidegate Systems" logo="logo-tidegate.svg" >}} -Tool annotations gave our reviewers the context they needed to approve agent -access in days instead of months. Our security team reads the annotations -directly during review, and that alone cut two meetings out of every rollout. -{{< /quote >}} -{{< /quotes >}} - -## Three quotes, static - -Three cards fit one view on desktop, so no carousel controls render. The -middle quote runs longer to show the shared attribution line in a static row. - -{{< quotes >}} -{{< quote name="Maren Odele" title="CTO" company="Lumenline" logo="logo-lumenline.svg" >}} -MCP let us wire our internal knowledge base into every agent we run. -{{< /quote >}} -{{< quote name="Priya Vanterpool" title="Head of Platform" company="Quartzfield Systems" logo="logo-quartzfield.svg" >}} -We replaced four bespoke plugin systems with one MCP server. Our team now -maintains a single surface instead of chasing SDK drift, and onboarding a new -integration went from a two week project to an afternoon. -{{< /quote >}} -{{< quote name="Jonas Ferrick" title="VP of Engineering" company="Harborlight Analytics" logo="logo-harborlight.svg" >}} -Enterprise-managed authorization removed the consent-prompt wall for our -analysts. -{{< /quote >}} -{{< /quotes >}} - -## Single quote - -{{< quotes >}} -{{< quote name="Sana Whitlow" title="Principal Engineer" company="Vexelworks" logo="logo-vexelworks.svg" >}} -The spec is readable, the SDKs are boring in the best way, and conformance -tests caught our edge cases before customers did. We moved our whole tool -surface to MCP in one sprint and have not looked back. -{{< /quote >}} -{{< /quotes >}} - -## No logo fallback - -Without a `logo` param the company name renders as a text wordmark. - -{{< quotes >}} -{{< quote name="Theo Marchbank" title="CPO" company="Copperfen Data" >}} -Our customers connect Copperfen to their agents themselves now. -{{< /quote >}} -{{< /quotes >}} - -## No title - -Without a `title` param the attribution is the name alone, no empty second -line. - -{{< quotes >}} -{{< quote name="Ines Kalvane" company="Tidegate Systems" logo="logo-tidegate.svg" >}} -Tool annotations gave our reviewers the context they needed to approve agent -access in days instead of months. -{{< /quote >}} -{{< /quotes >}} diff --git a/blog/content/posts/quote-component-test/logo-copperfen.svg b/blog/content/posts/quote-component-test/logo-copperfen.svg deleted file mode 100644 index edee90c37..000000000 --- a/blog/content/posts/quote-component-test/logo-copperfen.svg +++ /dev/null @@ -1,6 +0,0 @@ - diff --git a/blog/content/posts/quote-component-test/logo-harborlight.svg b/blog/content/posts/quote-component-test/logo-harborlight.svg deleted file mode 100644 index 2a9327aa9..000000000 --- a/blog/content/posts/quote-component-test/logo-harborlight.svg +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/blog/content/posts/quote-component-test/logo-lumenline.svg b/blog/content/posts/quote-component-test/logo-lumenline.svg deleted file mode 100644 index 94211e8af..000000000 --- a/blog/content/posts/quote-component-test/logo-lumenline.svg +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/blog/content/posts/quote-component-test/logo-quartzfield.svg b/blog/content/posts/quote-component-test/logo-quartzfield.svg deleted file mode 100644 index 83edee480..000000000 --- a/blog/content/posts/quote-component-test/logo-quartzfield.svg +++ /dev/null @@ -1,4 +0,0 @@ - diff --git a/blog/content/posts/quote-component-test/logo-tidegate.svg b/blog/content/posts/quote-component-test/logo-tidegate.svg deleted file mode 100644 index 27d962cf4..000000000 --- a/blog/content/posts/quote-component-test/logo-tidegate.svg +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/blog/content/posts/quote-component-test/logo-vexelworks.svg b/blog/content/posts/quote-component-test/logo-vexelworks.svg deleted file mode 100644 index 0d0d891a8..000000000 --- a/blog/content/posts/quote-component-test/logo-vexelworks.svg +++ /dev/null @@ -1,5 +0,0 @@ -