feat(content): 11 new SEO/GEO guide articles with per-article OG images
How-to cluster: create-mcp-server-without-code, claude-desktop-mcp-setup, chatgpt-mcp-connector (incl. honest Business/Enterprise write-connector plan limits), rest-api-to-mcp-server. Comparison cluster: mcp-server-hosting-pricing (5-platform matrix), composio-alternative, smithery-alternative — house style: explicitly state where competitors win. Technical/GEO cluster: mcp-transports-explained (SSE deprecation 2025-03-26), mcp-oauth-plain-english, mcp-server-security-checklist, and German DACH article mcp-server-ohne-code-erstellen (articleJsonLd gained optional inLanguage param). Every article: pageMetadata canonical, Article JSON-LD with Person author + image + wordCount, BreadcrumbList, FAQPage where applicable, 1200x630 OG image via shared helper, internal linking. Registry entries in lib/articles.ts feed guides index, sitemap and RSS automatically. Product claims sourced only from lib/seo.ts truth — no invented customers, SLAs or certifications. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SXUwmPVRTD8AKQtio6gCN5
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
import { JsonLd } from '@/components/json-ld';
|
||||
import { StaticCodeBlock } from '@/components/static-code-block';
|
||||
import { articleJsonLd, breadcrumbJsonLd, pageMetadata } from '@/lib/seo';
|
||||
import Link from 'next/link';
|
||||
import { ArticleShell, H2, Note, OL, P, Strong, Table, UL } from '../article-shell';
|
||||
|
||||
const PATH = '/guides/claude-desktop-mcp-setup';
|
||||
const TITLE = 'Connect a custom MCP server to Claude Desktop (step by step)';
|
||||
const DESCRIPTION =
|
||||
'How to add a remote MCP server to Claude Desktop: the config snippet, the OAuth flow on first use, and a troubleshooting table for 401s, missing servers and invisible tools.';
|
||||
|
||||
export const metadata = pageMetadata({ title: TITLE, description: DESCRIPTION, path: PATH });
|
||||
|
||||
const CONFIG_SNIPPET = `{
|
||||
"mcpServers": {
|
||||
"my-tools": {
|
||||
"url": "https://my-tools-a1.mcp.buildmymcpserver.com/mcp",
|
||||
"auth": "oauth2"
|
||||
}
|
||||
}
|
||||
}`;
|
||||
|
||||
const LOCAL_VS_REMOTE = `# Local (STDIO) — runs on your machine, per-machine setup
|
||||
"command": "npx", "args": ["-y", "@your/mcp-server"]
|
||||
|
||||
# Remote (Streamable HTTP) — hosted, one URL for every machine
|
||||
"url": "https://my-tools-a1.mcp.buildmymcpserver.com/mcp"`;
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<>
|
||||
<JsonLd
|
||||
data={articleJsonLd({
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
path: PATH,
|
||||
datePublished: '2026-07-08',
|
||||
authorName: 'Marco Sadjadi',
|
||||
wordCount: 1400,
|
||||
})}
|
||||
/>
|
||||
<JsonLd
|
||||
data={breadcrumbJsonLd([
|
||||
{ name: 'Home', path: '/' },
|
||||
{ name: 'Guides', path: '/guides' },
|
||||
{ name: TITLE, path: PATH },
|
||||
])}
|
||||
/>
|
||||
<ArticleShell
|
||||
title={TITLE}
|
||||
subtitle="Claude Desktop supports both local STDIO servers and remote servers over Streamable HTTP. Remote is the version that survives a laptop change — here is the exact setup, including what the OAuth consent screen is doing."
|
||||
updated="July 2026"
|
||||
>
|
||||
<H2>Local vs. remote — pick remote unless you have a reason</H2>
|
||||
<P>
|
||||
Most MCP tutorials wire up a <Strong>local STDIO server</Strong>: Claude Desktop spawns a
|
||||
process on your machine and talks to it over stdin/stdout. That works, but it is
|
||||
per-machine — every teammate repeats the setup, secrets live in local config files, and
|
||||
nothing works from a second device. A <Strong>remote server over Streamable HTTP</Strong>{' '}
|
||||
is one URL that every installation shares, with auth handled by OAuth instead of
|
||||
plaintext keys in a JSON file.
|
||||
</P>
|
||||
<StaticCodeBlock code={LOCAL_VS_REMOTE} label="the difference in config terms" />
|
||||
|
||||
<H2>Step 1 — get a server URL</H2>
|
||||
<P>
|
||||
You need a live MCP endpoint. If you already run one, use its URL. If not, you can{' '}
|
||||
<Link href="/guides/create-mcp-server-without-code" className="text-[--color-accent] hover:underline">
|
||||
generate one from a prompt
|
||||
</Link>{' '}
|
||||
or fork a working one from{' '}
|
||||
<Link href="/templates" className="text-[--color-accent] hover:underline">
|
||||
the template gallery
|
||||
</Link>{' '}
|
||||
— either way you end up with an OAuth-protected URL like{' '}
|
||||
<Strong>https://my-tools-a1.mcp.buildmymcpserver.com/mcp</Strong>.
|
||||
</P>
|
||||
|
||||
<H2>Step 2 — add the server to Claude Desktop</H2>
|
||||
<OL>
|
||||
<li>
|
||||
Open Claude Desktop settings and go to the connectors/MCP section (on recent versions:
|
||||
Settings → Connectors → Add custom connector), or edit{' '}
|
||||
<Strong>claude_desktop_config.json</Strong> directly.
|
||||
</li>
|
||||
<li>Add the server entry:</li>
|
||||
</OL>
|
||||
<StaticCodeBlock code={CONFIG_SNIPPET} label="claude_desktop_config.json" />
|
||||
<OL>
|
||||
<li value={3}>Restart Claude Desktop. Config is read at startup, not live.</li>
|
||||
</OL>
|
||||
<Note>
|
||||
Claude Desktop's settings UI changes between releases; the JSON config path is the stable
|
||||
fallback. On macOS it lives at{' '}
|
||||
<Strong>~/Library/Application Support/Claude/claude_desktop_config.json</Strong>, on
|
||||
Windows at <Strong>%APPDATA%\Claude\claude_desktop_config.json</Strong>.
|
||||
</Note>
|
||||
|
||||
<H2>Step 3 — the OAuth flow on first use</H2>
|
||||
<P>
|
||||
The first time Claude touches the server it will receive a <Strong>401</Strong> — that is
|
||||
correct behavior, not an error. The client then discovers the authorization server,
|
||||
registers itself via Dynamic Client Registration, and opens a browser window for consent.
|
||||
You approve once; the client stores the token and refreshes it silently afterwards.
|
||||
</P>
|
||||
<P>
|
||||
Under the hood this is the OAuth 2.1 handshake the MCP spec requires for remote servers:
|
||||
PKCE so the code exchange cannot be intercepted, and Resource Indicators (RFC 8707) so a
|
||||
token issued for this server cannot be replayed against another. Details in{' '}
|
||||
<Link href="/docs/oauth" className="text-[--color-accent] hover:underline">
|
||||
the OAuth documentation
|
||||
</Link>
|
||||
.
|
||||
</P>
|
||||
|
||||
<H2>Step 4 — verify the tools are there</H2>
|
||||
<UL>
|
||||
<li>Open a new conversation and check the tools/connectors icon — your server should be listed with its tools.</li>
|
||||
<li>
|
||||
Ask Claude directly: <em>“Use the search_pages tool to find X.”</em> Naming the tool
|
||||
forces Claude to attempt the call instead of answering from memory.
|
||||
</li>
|
||||
<li>Watch your server's dashboard logs — you should see the tool call arrive with latency and status.</li>
|
||||
</UL>
|
||||
|
||||
<H2>Troubleshooting</H2>
|
||||
<Table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Symptom</th>
|
||||
<th>Likely cause</th>
|
||||
<th>Fix</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Server never appears in the client</td>
|
||||
<td>Config JSON is invalid, or Claude was not restarted</td>
|
||||
<td>
|
||||
Validate the JSON (trailing commas are the classic), restart Claude Desktop fully
|
||||
(quit, not close window).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Endless 401 loop, consent screen never opens</td>
|
||||
<td>URL points at the server root instead of the /mcp endpoint</td>
|
||||
<td>Use the full endpoint URL ending in /mcp, exactly as the install snippet shows.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Consent worked, tools still missing</td>
|
||||
<td>Server is deployed but tool listing failed on connect</td>
|
||||
<td>
|
||||
Check the server's live logs for an initialize/list_tools error; redeploy if the
|
||||
container restarted with a bad secret.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tool listed, every call errors</td>
|
||||
<td>Upstream credential (e.g. your API key) is wrong or expired</td>
|
||||
<td>
|
||||
Update the secret in the dashboard — secrets are injected at runtime, so a redeploy
|
||||
picks up the new value. They are never shown back, so re-enter rather than inspect.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Worked yesterday, 401 today</td>
|
||||
<td>Token expired and silent refresh failed</td>
|
||||
<td>Remove and re-add the connector to force a fresh OAuth flow.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</Table>
|
||||
|
||||
<H2>One server, every client</H2>
|
||||
<P>
|
||||
The same URL works in Cursor, VS Code Copilot, Continue.dev and{' '}
|
||||
<Link href="/guides/chatgpt-mcp-connector" className="text-[--color-accent] hover:underline">
|
||||
ChatGPT custom connectors
|
||||
</Link>{' '}
|
||||
— the point of hosting a remote MCP server is that the client config is the only
|
||||
per-client step left. If you hit a case this guide does not cover, the{' '}
|
||||
<Link href="/docs/faq" className="text-[--color-accent] hover:underline">
|
||||
docs FAQ
|
||||
</Link>{' '}
|
||||
collects the rarer ones.
|
||||
</P>
|
||||
</ArticleShell>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user