blog: add 5 tips for building MCP Apps that work#6855
Conversation
- New blog post co-authored with Matthew Wang (MCPJam) - Add Matt Wang as new author in authors.yml - Covers: host environment adaptation, data flow control, loading/error states, model sync, and tool visibility
|
There was a problem hiding this comment.
Pull request overview
Adds a new blog post covering five practical tips for building MCP Apps, including supporting diagrams/screenshots and a new co-author entry.
Changes:
- Add a new blog post: “5 Tips for Building MCP Apps That Work”.
- Add Matthew Wang as a blog author in
authors.yml. - Add new blog images used by the post (banner, flow diagram, loading state screenshot).
Reviewed changes
Copilot reviewed 2 out of 6 changed files in this pull request and generated 8 comments.
| File | Description |
|---|---|
| documentation/blog/authors.yml | Adds new matt author profile for the co-authored post. |
| documentation/blog/2026-01-30-5-tips-building-mcp-apps/index.md | New blog content, code examples, and social metadata for the post. |
| documentation/blog/2026-01-30-5-tips-building-mcp-apps/loading-state.png | New image asset referenced by the post. |
documentation/blog/2026-01-30-5-tips-building-mcp-apps/index.md
Outdated
Show resolved
Hide resolved
documentation/blog/2026-01-30-5-tips-building-mcp-apps/index.md
Outdated
Show resolved
Hide resolved
documentation/blog/2026-01-30-5-tips-building-mcp-apps/index.md
Outdated
Show resolved
Hide resolved
documentation/blog/2026-01-30-5-tips-building-mcp-apps/index.md
Outdated
Show resolved
Hide resolved
documentation/blog/2026-01-30-5-tips-building-mcp-apps/index.md
Outdated
Show resolved
Hide resolved
Co-authored-by: Copilot <[email protected]>
documentation/blog/2026-01-30-5-tips-building-mcp-apps/index.md
Outdated
Show resolved
Hide resolved
Co-authored-by: Copilot <[email protected]>
| import { useApp } from "@modelcontextprotocol/ext-apps/react"; | ||
|
|
||
| function CocktailApp() { | ||
| const [cocktail, setCocktail] = useState<CocktailData | null>(null); | ||
|
|
There was a problem hiding this comment.
The loading-state React example uses useState but doesn't import it, so the snippet as written won't run; add useState to the React import (or qualify it) to keep the example self-contained.
| ui: { resourceUri: "ui://cocktail/cocktail-recipe-widget.html" }, | ||
| visibility: ["model", "app"], |
There was a problem hiding this comment.
In this tool definition, visibility is placed at _meta.visibility, but elsewhere in the post it is nested under _meta.ui.visibility; hosts in this repo read UI metadata from _meta.ui.*, so move visibility under the ui object for consistency and to match how the host discovers UI metadata.
| ui: { resourceUri: "ui://cocktail/cocktail-recipe-widget.html" }, | |
| visibility: ["model", "app"], | |
| ui: { resourceUri: "ui://cocktail/cocktail-recipe-widget.html", visibility: ["model", "app"] }, |
| return { | ||
| content: [ | ||
| { type: "text", text: `Could not load cocktail` }, | ||
| ], | ||
| error |
There was a problem hiding this comment.
The catch block returns the raw error object from the backend to both the model and the MCP App view, which can expose internal details such as stack traces, database errors, or configuration information to end users. An attacker can trigger failing requests (e.g., invalid IDs or crafted payloads) to harvest these internal error messages and use them to map the backend or discover weaknesses. Instead, return a generic, user-safe error message and log the detailed error server-side, ensuring the tool result only contains sanitized error information.
| return { | |
| content: [ | |
| { type: "text", text: `Could not load cocktail` }, | |
| ], | |
| error | |
| // Log the detailed error server-side instead of returning it to the client. | |
| console.error("Failed to load cocktail", error); | |
| return { | |
| content: [ | |
| { type: "text", text: `Could not load cocktail` }, | |
| ], | |
| error: { | |
| message: "Failed to load cocktail.", | |
| }, |
* main: fix: fixed the broken release (#6887) feat: Streamable HTTP transport for ACP + goose-acp usage (#6741) Add Laminar for Observability (#6514) Missed a couple of places that hard code J for the newline key (#6853) fix(ui): preserve working directory when creating new chat (#6789) blog: add 5 tips for building MCP Apps that work (#6855) docs: session isolation (#6846) upgrade react and electron to latest (#6845) Fix: Small update UI settings prompt injection (#6830) Remove autogenerated .gooseignore files that don't belong in repo (#6824) Fix case-insensitive matching for builtin extension names (#6825) docs: cli newline keybinding (#6823) Update version to 1.22.0 (#6821) Refactor: move persisting extension to session outside of route (#6685) acp: load configured extensions and refactor tests (#6803)
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot <[email protected]>
Type of Change