Fetching Data from an MCP Server in Your Frontend A developer outlined two approaches for pulling data from Model Context Protocol (MCP) servers into a frontend web app: running the official TypeScript SDK directly in the browser over Streamable HTTP, or routing calls through a thin backend proxy that holds MCP credentials and enforces per-user authorization and a tool allowlist. The writeup includes working Express and React code showing JSON-RPC 2.0 tools/call and resources/read requests, error handling, and passing through Server-Sent Events progress notifications. MCP servers are usually discussed as tools for AI assistants, but the same servers can feed your web app directly. A dashboard can call the same search orders tool your agent uses, so both get one consistent data layer. This article shows how a frontend gets that data and what to watch for. Option 1: an MCP client SDK in the browser. The official TypeScript SDK @modelcontextprotocol/sdk can run in the browser and talk to a remote server over Streamable HTTP. It's quick for demos and internal tools, but the browser then needs a token for the MCP server and the server must allow CORS. Option 2: a thin backend proxy recommended . Your backend runs the MCP client and exposes ordinary endpoints like /api/tools/search orders . The frontend never sees MCP credentials, you check the user's session before every call, and you can allow only specific tools. MCP uses JSON-RPC 2.0. After an initialize handshake, the two calls a frontend cares about most look like this. Calling a tool: { "jsonrpc": "2.0", "id": 7, "method": "tools/call", "params": { "name": "search orders", "arguments": { "customer": "Acme" } } } A successful result: { "jsonrpc": "2.0", "id": 7, "result": { "content": { "type": "text", "text": " {\"id\":101,\"total\":250} " } , "isError": false } } Reading a resource uses resources/read with a URI, such as { "uri": "orders://recent" } , and returns contents with text or binary data. Use tools/list and resources/list to discover what's available. python import express from "express"; import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; const client = new Client { name: "web-proxy", version: "1.0.0" } ; await client.connect new StreamableHTTPClientTransport new URL process.env.MCP URL ; const ALLOWED = new Set "search orders", "get order" ; const app = express ; app.use express.json ; app.post "/api/tools/:name", async req, res = { if req.headers.authorization return res.status 401 .json { error: "Sign in first" } ; if ALLOWED.has req.params.name return res.status 403 .json { error: "Tool not allowed" } ; try { const result = await client.callTool { name: req.params.name, arguments: req.body } ; if result.isError return res.status 422 .json { error: result.content } ; res.json result.content ; } catch e { res.status 502 .json { error: "MCP server unavailable" } ; } } ; app.listen 3000 ; js import { useState } from "react"; export function OrderSearch { const rows, setRows = useState