Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
dfd82e2
docs(blog): fix resultType value in 2026-07-28 RC post
kerlenton Jul 24, 2026
0f077dc
docs/authorization: resolve demo Python server 401 error
jhauga Jul 24, 2026
091a265
docs/authorization: resolve demo Python server 401 error
jhauga Jul 24, 2026
1bee97a
docs(community): add MCP Apps Working Group charter
liady Jul 25, 2026
a4ea0ac
Merge pull request #3126 from jhauga/docs
dend Jul 27, 2026
465313b
build(deps): bump actions/labeler from 6 to 7
dependabot[bot] Jul 27, 2026
b7c4ce4
build(deps-dev): bump typescript-eslint from 8.64.0 to 8.65.0 (#3136)
dependabot[bot] Jul 27, 2026
3b205e9
build(deps-dev): bump postcss
dependabot[bot] Jul 27, 2026
9d92d15
build(deps-dev): bump eslint from 10.7.0 to 10.8.0 (#3135)
dependabot[bot] Jul 27, 2026
31eefec
build(deps-dev): bump prettier from 3.9.5 to 3.9.6 (#3137)
dependabot[bot] Jul 27, 2026
6e8bd2c
Add quotes shortcode for testimonial cards on the blog
claude Jul 27, 2026
43f218c
Merge pull request #3125 from kerlenton/fix/rc-blog-input-required
localden Jul 27, 2026
d741d3f
Merge pull request #3134 from modelcontextprotocol/dependabot/github_…
localden Jul 27, 2026
50f5bcb
Merge pull request #3138 from modelcontextprotocol/dependabot/npm_and…
localden Jul 27, 2026
118388d
Align quote attributions to a shared start line
claude Jul 27, 2026
ae681e2
Break the quote strip out of the prose column
claude Jul 27, 2026
d07b58f
Set quote attribution and text-logo fallback to regular weight
claude Jul 27, 2026
560d843
Bold the attribution name and move the title to its own line
claude Jul 27, 2026
4549a6a
Remove quote component test post
claude Jul 27, 2026
7d6c7b8
Merge pull request #3141 from modelcontextprotocol/feat/quote-component
localden Jul 27, 2026
ae0ba4d
Merge branch 'main' into mcp-apps-charter
dsp-ant Jul 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ jobs:
label:
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v6
- uses: actions/labeler@v7
with:
sync-labels: false
256 changes: 256 additions & 0 deletions blog/assets/css/extended/quotes.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
/* ─── 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. */

/* 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 {
--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 {
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;
}

/* 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 {
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;
}

/* 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: 16px;
}
}

/* 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: 400;
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;
}

/* 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
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;
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);
}
2 changes: 1 addition & 1 deletion blog/content/posts/2026-05-21-mcp-2026-07-28-rc.md
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
39 changes: 39 additions & 0 deletions blog/layouts/shortcodes/quote.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{{- /*
A single testimonial card. Use inside a `quotes` block.

Params:
name - person's 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.
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" -}}
<figure class="mcp-quote">
{{- with $logo -}}
{{- with $.Page.Resources.GetMatch . -}}
{{- if eq .MediaType.SubType "svg" -}}
<span class="mcp-quote-logo" role="img" aria-label="{{ $company }}">{{ .Content | safeHTML }}</span>
{{- else -}}
<span class="mcp-quote-logo"><img src="{{ .RelPermalink }}" alt="{{ $company }}" loading="lazy"></span>
{{- end -}}
{{- else -}}
<span class="mcp-quote-logo"><img src="{{ . }}" alt="{{ $company }}" loading="lazy"></span>
{{- end -}}
{{- else -}}
<span class="mcp-quote-logo mcp-quote-logo-text">{{ $company }}</span>
{{- end }}
<blockquote class="mcp-quote-text">&ldquo;{{ trim .Inner " \n" | .Page.RenderString }}&rdquo;</blockquote>
<figcaption class="mcp-quote-attrib">
<span class="mcp-quote-attrib-name">{{ $name }}</span>
{{- with $title }}
<span class="mcp-quote-attrib-title">{{ . }}</span>
{{- end }}
</figcaption>
</figure>
Loading