import { JsonLd } from '@/components/json-ld';
import { StaticCodeBlock } from '@/components/static-code-block';
import { articleJsonLd, breadcrumbJsonLd, faqJsonLd, pageMetadata } from '@/lib/seo';
import Link from 'next/link';
import { ArticleShell, H2, Note, OL, P, Strong, UL } from '../article-shell';

const PATH = '/guides/create-mcp-server-without-code';
const TITLE = 'How to create an MCP server without writing code (2026)';
const DESCRIPTION =
  'Turn a plain-language description into a hosted, OAuth-protected MCP server — no SDK, no Docker, no TypeScript. What works, what the limits are, and when you still need code.';

export const metadata = pageMetadata({ title: TITLE, description: DESCRIPTION, path: PATH });

const ARTICLE_FAQ = [
  {
    q: 'Do I really write zero code to create an MCP server?',
    a: 'Yes — you describe the tools in natural language. The platform generates a TypeScript MCP server, runs static checks against banned patterns, builds a Docker image and deploys it behind OAuth 2.1. You never touch the code unless you want to: the full source is exportable at any time.',
  },
  {
    q: 'How long does generation take?',
    a: 'Spec to image to live URL typically completes in 45–90 seconds. You watch the build log stream live in the dashboard.',
  },
  {
    q: 'Which AI clients can use a no-code MCP server?',
    a: 'Anything that speaks the MCP spec over Streamable HTTP: Claude Desktop, Cursor, ChatGPT custom connectors, VS Code Copilot and Continue.dev. You get a copy-paste install snippet for each.',
  },
  {
    q: 'What does it cost to try?',
    a: 'The free tier includes one hosted server and 100,000 tool calls per month — no credit card. The full TypeScript source of every server you build is exportable, so there is no lock-in.',
  },
];

const PROMPT_EXAMPLE = `Create an MCP server that searches our Notion workspace.
Tools: search_pages, get_page_content.
Auth: NOTION_API_KEY.`;

const SNIPPET_EXAMPLE = `{
  "mcpServers": {
    "notion": {
      "url": "https://notion-x9.mcp.buildmymcpserver.com/mcp",
      "auth": "oauth2"
    }
  }
}`;

export default function Page() {
  return (
    <>
      <JsonLd
        data={articleJsonLd({
          title: TITLE,
          description: DESCRIPTION,
          path: PATH,
          datePublished: '2026-07-08',
          authorName: 'Marco Sadjadi',
          wordCount: 1500,
        })}
      />
      <JsonLd
        data={breadcrumbJsonLd([
          { name: 'Home', path: '/' },
          { name: 'Guides', path: '/guides' },
          { name: TITLE, path: PATH },
        ])}
      />
      <JsonLd data={faqJsonLd(ARTICLE_FAQ)} />
      <ArticleShell
        title={TITLE}
        subtitle="The Model Context Protocol lets AI assistants call your tools — but the official route to a server means an SDK, a transport, an auth layer and somewhere to host it. Here is the route that skips all four, and an honest list of where it stops."
        updated="July 2026"
      >
        <H2>What “no code” actually has to cover</H2>
        <P>
          An MCP server that works outside your laptop is more than tool functions. To let Claude,
          Cursor or ChatGPT call it from anywhere, you need four things: the{' '}
          <Strong>server code</Strong> itself (tool definitions plus handlers), a{' '}
          <Strong>remote transport</Strong> (Streamable HTTP — the STDIO servers most tutorials
          build only work locally), an <Strong>auth layer</Strong> (the MCP spec requires OAuth 2.1
          for remote servers), and <Strong>hosting</Strong> that keeps the process alive. A no-code
          claim that only generates the first item leaves you with three engineering problems. The
          flow below covers all four.
        </P>

        <H2>Step 1 — describe the tool in plain language</H2>
        <P>
          You write a prompt, not a spec. Name the tools you want, the credentials they need, and
          what they should do. A working example:
        </P>
        <StaticCodeBlock code={PROMPT_EXAMPLE} label="prompt" />
        <P>
          Three lines is enough because the generator asks the model for a structured spec, not
          prose: tool names, input schemas, the API calls behind them, and which environment
          variables hold secrets. If the description is ambiguous, you see the interpreted spec
          before anything builds and can edit it.
        </P>

        <H2>Step 2 — generation and static checks</H2>
        <P>
          From the spec, the platform renders a TypeScript MCP server. Before anything runs, the
          generated code goes through static checks against banned patterns — no
          <Strong> child processes, no filesystem escapes, no calls to unlisted hosts</Strong>. This
          matters more in a no-code flow than in a hand-written one: you did not read the code, so
          the platform has to.
        </P>
        <P>
          The output is real, exportable TypeScript. If you cancel your account tomorrow, you can{' '}
          <Link href="/docs/authoring" className="text-[--color-accent] hover:underline">
            take the source
          </Link>{' '}
          and run it yourself — there is no proprietary runtime inside.
        </P>

        <H2>Step 3 — build and deploy</H2>
        <P>
          The server is packaged into a Docker image and deployed to its own isolated container —
          one container per server, so a bug in your Notion tool cannot see your Stripe tool's
          credentials. Secrets you provide (like <Strong>NOTION_API_KEY</Strong>) are encrypted
          with AES-256-GCM at rest and injected as environment variables only at runtime. They are
          never logged and never echoed back into the dashboard.
        </P>
        <P>
          The whole pipeline — spec, render, checks, image build, deploy — typically completes in{' '}
          <Strong>45–90 seconds</Strong>, streamed live to the dashboard so you can watch each
          stage pass.
        </P>

        <H2>Step 4 — the OAuth-protected URL</H2>
        <P>
          The deployed server is a public Streamable HTTP endpoint, but every request is gated by
          OAuth 2.1 before it reaches your container. The control plane acts as the authorization
          server — PKCE, Dynamic Client Registration (RFC 7591) and Resource Indicators (RFC 8707)
          — which is exactly the handshake modern MCP clients expect. You never configure any of
          it;{' '}
          <Link href="/docs/oauth" className="text-[--color-accent] hover:underline">
            the OAuth docs
          </Link>{' '}
          explain what happens under the hood.
        </P>

        <H2>Step 5 — install in your client</H2>
        <P>The dashboard renders a copy-paste snippet per client. For Claude Desktop:</P>
        <StaticCodeBlock code={SNIPPET_EXAMPLE} label="claude_desktop_config.json" />
        <P>
          On first use the client opens the OAuth consent flow in your browser; approve it once and
          the tools appear. The same server works in Cursor, ChatGPT custom connectors, VS Code
          Copilot and Continue.dev — see the client-specific walkthroughs for{' '}
          <Link href="/guides/claude-desktop-mcp-setup" className="text-[--color-accent] hover:underline">
            Claude Desktop
          </Link>{' '}
          and{' '}
          <Link href="/guides/chatgpt-mcp-connector" className="text-[--color-accent] hover:underline">
            ChatGPT
          </Link>
          .
        </P>

        <H2>What you cannot do without code — honest limits</H2>
        <UL>
          <li>
            <Strong>Complex business logic.</Strong> Generation is good at “call this API, shape
            the response”. Multi-step workflows with branching state, retries with compensation, or
            heavy data transformation deserve hand-written code. Export the generated source and
            extend it — that is the intended escape hatch.
          </li>
          <li>
            <Strong>Unusual protocols.</Strong> Tools that need gRPC, raw TCP, or binary SDKs are
            out of scope for prompt-generation; the generated servers speak HTTP to upstream APIs.
          </li>
          <li>
            <Strong>Long-running jobs.</Strong> A tool call is a request/response. Anything that
            takes minutes belongs in a queue you own, with the MCP tool submitting and polling.
          </li>
          <li>
            <Strong>Compliance paperwork.</Strong> If procurement requires SOC 2 or HIPAA
            certification today, a generated-and-hosted server will not check that box — no such
            certifications are claimed. Self-hosting the exported source inside your own audited
            infrastructure is the workaround.
          </li>
        </UL>
        <Note>
          Rule of thumb: if you can describe the tool in three sentences, generation gets you to
          production. If your description needs a diagram, write code — or generate first, export,
          then edit.
        </Note>

        <H2>Try it against a real API first</H2>
        <OL>
          <li>
            Pick one API you use daily — Notion, GitHub, your own REST backend (
            <Link href="/guides/rest-api-to-mcp-server" className="text-[--color-accent] hover:underline">
              wrapping a REST API
            </Link>{' '}
            is the most common first server).
          </li>
          <li>Write the three-line prompt: tools, credentials, behavior.</li>
          <li>Watch the build, paste the snippet, ask your assistant to use the tool.</li>
        </OL>
        <P>
          The{' '}
          <Link href="/pricing" className="text-[--color-accent] hover:underline">
            free tier
          </Link>{' '}
          covers one server and 100,000 tool calls a month, which is more than enough to find out
          whether the no-code route fits your case. If it does not, you have lost ten minutes and
          gained a working reference implementation to export. Browse{' '}
          <Link href="/templates" className="text-[--color-accent] hover:underline">
            the template gallery
          </Link>{' '}
          if you would rather fork a working server than write a prompt.
        </P>

        <H2>FAQ</H2>
        {ARTICLE_FAQ.map((f) => (
          <div key={f.q} className="mt-5">
            <h3 className="text-[15px] font-semibold tracking-tight text-[--color-fg]">{f.q}</h3>
            <p className="mt-1.5 text-[14px] leading-relaxed text-[--color-fg-muted]">{f.a}</p>
          </div>
        ))}
      </ArticleShell>
    </>
  );
}
