{"id":110,"date":"2026-09-17T01:44:22","date_gmt":"2026-09-16T17:44:22","guid":{"rendered":"https:\/\/wp.qoraapi.com\/model-context-protocol-mcp\/"},"modified":"2026-09-20T02:51:36","modified_gmt":"2026-09-19T18:51:36","slug":"model-context-protocol-mcp","status":"publish","type":"post","link":"https:\/\/qoraapi.com\/blog\/model-context-protocol-mcp\/","title":{"rendered":"What Is the Model Context Protocol (MCP)? Connect Your AI to Real Tools"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">The Model Context Protocol (MCP) is an open standard that lets any AI application plug into tools and data through one client\/server interface. Instead of writing a separate Slack, database, or filesystem integration for every assistant, you write one MCP server \u2014 and every MCP-compatible client can use it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This guide covers what the protocol actually specifies, how it composes with <a href=\"https:\/\/qoraapi.com\/blog\/ai-function-calling-tool-use\/\">function calling<\/a> rather than replacing it, and a minimal server you can run in five minutes.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The problem MCP solves: N clients \u00d7 M integrations<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Before MCP, every AI host had its own plugin format. Claude Desktop, an IDE assistant, a LangChain script, and your internal chatbot each needed their own adapter for Slack, Postgres, Jira, and the local filesystem. Five hosts and eight data sources is 40 bespoke adapters, each with its own auth handling, retry logic, and schema quirks.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That matrix has a second, worse cost: maintenance. When Slack changes a response shape or an OAuth scope, you patch every adapter separately. MCP collapses the matrix to a sum. Five hosts plus eight servers is 13 implementations, and one vendor change means one patch.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">There is a third cost that only shows up once you build <a href=\"https:\/\/qoraapi.com\/blog\/ai-agents-tool-use\/\">AI agents<\/a>: discovery. An agent that can only call the tools you hardcoded at build time cannot use a new tool without a redeploy. MCP servers advertise their capabilities at runtime, so a client can enumerate what is available on each connection and react when the list changes.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What MCP is: client\/server over JSON-RPC 2.0<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">MCP has three roles. The <strong>host<\/strong> is the AI application (an IDE, a chat app, your backend). The <strong>client<\/strong> is a connector inside the host, one per server. The <strong>server<\/strong> is a program that exposes capabilities. Client and server exchange JSON-RPC 2.0 messages \u2014 requests with an <code>id<\/code>, responses, and one-way notifications.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Every connection begins with an <code>initialize<\/code> handshake. The client sends a date-stamped protocol version and the capabilities it supports; the server replies with its own. This is the design decision that makes MCP durable: a server can add a feature that older clients simply never see, instead of breaking them. Protocol versions are dates, not semantic numbers, so negotiation is a comparison rather than a compatibility guess.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The methods you will actually see in logs:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Tools<\/strong> \u2014 <code>tools\/list<\/code>, <code>tools\/call<\/code>. Model-controlled actions with side effects.<\/li>\n<li><strong>Resources<\/strong> \u2014 <code>resources\/list<\/code>, <code>resources\/read<\/code>, <code>resources\/subscribe<\/code>. Addressable read-only data.<\/li>\n<li><strong>Prompts<\/strong> \u2014 <code>prompts\/list<\/code>, <code>prompts\/get<\/code>. Reusable templates the user picks.<\/li>\n<li><strong>Change notifications<\/strong> \u2014 <code>notifications\/tools\/list_changed<\/code>, so clients re-fetch instead of caching forever.<\/li>\n<li><strong>Server-to-client calls<\/strong> \u2014 <code>sampling\/createMessage<\/code> (the server asks the host&#8217;s model to generate) and <code>elicitation\/create<\/code> (the server asks the user for a missing argument). These are the least-known part of the spec and the reason a plain HTTP API wrapper is not an MCP server.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Two transports carry these messages, and choosing between them is a deployment decision, not a preference:<\/p>\n\n\n\n<figure class=\"wp-block-table is-style-stripes\"><table class=\"has-fixed-layout\"><thead><tr><th>Transport<\/th><th>How it works<\/th><th>Use it when<\/th><th>Auth boundary<\/th><\/tr><\/thead><tbody><tr><td>stdio<\/td><td>JSON-RPC over the stdin\/stdout of a child process the host spawns<\/td><td>Local developer tools, IDE and desktop clients, filesystem or shell access<\/td><td>OS process boundary; no network exposure<\/td><\/tr><tr><td>Streamable HTTP<\/td><td>JSON-RPC over HTTP POST, with optional SSE streaming on the same endpoint<\/td><td>Remote or shared servers, multi-tenant SaaS, anything behind a load balancer<\/td><td>OAuth 2.1 bearer tokens with audience validation<\/td><\/tr><tr><td>HTTP+SSE (legacy)<\/td><td>Long-lived SSE stream for server messages plus a separate POST endpoint for client messages<\/td><td>Only for pre-2025 servers you cannot upgrade<\/td><td>Two endpoints to secure and correlate<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Streamable HTTP replaced the original HTTP+SSE transport because two endpoints made session correlation and horizontal scaling painful. If you are writing a new remote server today, use Streamable HTTP.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">MCP vs function calling: interface vs invocation<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">These are routinely described as competitors. They are not, and the distinction matters because it tells you what each one can and cannot fix.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Function calling is a model behavior.<\/strong> You place a JSON Schema in the request; the model may answer with a structured call object instead of prose; your code executes it. It specifies nothing about where that function lives, how it authenticates, or how your app learned it exists.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>MCP is an integration protocol.<\/strong> A server advertises capabilities, a client discovers them, and both sides speak JSON-RPC 2.0 over a negotiated transport. It specifies nothing about how the model decides to call anything.<\/p>\n\n\n\n<figure class=\"wp-block-table is-style-stripes\"><table class=\"has-fixed-layout\"><thead><tr><th>Dimension<\/th><th>Function calling<\/th><th>MCP<\/th><\/tr><\/thead><tbody><tr><td>What it standardizes<\/td><td>The model&#8217;s output format for &#8220;call this with these arguments&#8221;<\/td><td>The interface between an AI app and a tool provider<\/td><\/tr><tr><td>Who defines the contract<\/td><td>You, per provider, inside every request payload<\/td><td>The server, discovered at runtime via <code>tools\/list<\/code><\/td><\/tr><tr><td>Where tools live<\/td><td>In your process<\/td><td>Anywhere: local child process or remote service<\/td><\/tr><tr><td>Discovery, auth, lifecycle<\/td><td>Not covered<\/td><td>Covered \u2014 handshake, capability negotiation, OAuth<\/td><\/tr><tr><td>Reuse across apps<\/td><td>Copy-paste per app<\/td><td>Any MCP client works unchanged<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The composition point is concrete: the output of <code>tools\/list<\/code> is already JSON Schema, and the input to function calling is already JSON Schema. Converting one to the other is a rename, which is exactly what the bridge later in this article does.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Three consequences that surprise people implementing this for the first time:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>MCP does not make a model smarter.<\/strong> If your model picks the wrong tool, MCP will not fix it. MCP fixes integration, not reasoning \u2014 validate tool-selection quality separately before shipping an agent.<\/li>\n<li><strong>You can use MCP with zero function calling.<\/strong> Resources and prompts need no model-side invocation. A client that only reads resources is fully compliant.<\/li>\n<li><strong>Some providers now accept a remote MCP server URL directly as a tool.<\/strong> The provider hosts the client loop and you write no bridge. Decision rule: use provider-hosted MCP for prototypes and read-only servers; run your own client when you need allowlists, audit logs, or a human approval step, because hosted loops give you little control over which tools are exposed or when the loop terminates.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Anatomy of an MCP server: tools, resources, prompts<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The three primitives differ by <em>who decides to use them<\/em>, which is the fastest way to classify anything you are building:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Tool<\/strong> \u2014 the model decides. Has side effects, takes validated arguments, returns content. Anything a user would expect to be asked about first is a tool.<\/li>\n<li><strong>Resource<\/strong> \u2014 the app or user decides. Read-only, addressed by URI, and attachable to context before the model is even called.<\/li>\n<li><strong>Prompt<\/strong> \u2014 the user decides. A named template the client surfaces, typically as a slash command.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Here is a complete, runnable server using the official Python SDK. It exposes two tools, one resource, and one prompt over stdio:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># server.py \u2014 minimal MCP server (official Python SDK)\n# pip install \"mcp[cli]\"\nfrom mcp.server.fastmcp import FastMCP\n\nmcp = FastMCP(\"repo-tools\")\n\n@mcp.tool()\ndef read_file(path: str) -&gt; str:\n    \"\"\"Read a UTF-8 text file from the workspace.\"\"\"\n    with open(path, encoding=\"utf-8\") as f:\n        return f.read()\n\n@mcp.tool()\ndef count_lines(path: str) -&gt; int:\n    \"\"\"Count the lines in a text file.\"\"\"\n    with open(path, encoding=\"utf-8\") as f:\n        return sum(1 for _ in f)\n\n@mcp.resource(\"repo:\/\/readme\")\ndef readme() -&gt; str:\n    \"\"\"Expose the README as an addressable, read-only resource.\"\"\"\n    with open(\"README.md\", encoding=\"utf-8\") as f:\n        return f.read()\n\n@mcp.prompt()\ndef review(file: str) -&gt; str:\n    \"\"\"A reusable template the user can invoke by name.\"\"\"\n    return f\"Review {file} for bugs and list concrete fixes.\"\n\nif __name__ == \"__main__\":\n    mcp.run()   # stdio transport; use transport=\"streamable-http\" to serve remotely\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Two details worth copying into production. First, the docstring becomes the tool description the model sees \u2014 treat it as prompt engineering, not documentation. Second, MCP lets a tool declare annotations such as <code>readOnlyHint<\/code>, <code>destructiveHint<\/code>, <code>idempotentHint<\/code>, and <code>openWorldHint<\/code>. Clients use these to auto-approve safe reads and force confirmation on destructive or internet-reaching calls. They are hints from the server, so they improve UX but are not a security boundary.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Connecting an AI app to an MCP server<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The client side is shorter than most people expect, and the identical code works against any server \u2014 local or remote, yours or someone else&#8217;s:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># client.py \u2014 discover and call tools on any MCP server\nimport asyncio\nfrom mcp import ClientSession, StdioServerParameters\nfrom mcp.client.stdio import stdio_client\n\nasync def main():\n    params = StdioServerParameters(command=\"python\", args=[\"server.py\"])\n    async with stdio_client(params) as (read, write):\n        async with ClientSession(read, write) as session:\n            await session.initialize()                 # negotiate capabilities\n\n            tools = await session.list_tools()\n            for t in tools.tools:\n                print(t.name, \"-\", t.description)\n\n            result = await session.call_tool(\"count_lines\", {\"path\": \"README.md\"})\n            print(result.content[0].text)\n\nasyncio.run(main())\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The lifecycle is <code>initialize<\/code> \u2192 <code>initialized<\/code> notification \u2192 <code>tools\/list<\/code> \u2192 <code>tools\/call<\/code>. If you are wiring a desktop or IDE client instead of writing code, the configuration is the same shape everywhere \u2014 a command, arguments, and environment variables:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"mcpServers\": {\n    \"repo-tools\": {\n      \"command\": \"python\",\n      \"args\": [\"C:\/tools\/server.py\"],\n      \"env\": { \"WORKSPACE\": \"C:\/repo\" }\n    }\n  }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">That file is why MCP spread quickly: the same server block drops into desktop chat clients and IDE assistants, which is also how you <a href=\"https:\/\/qoraapi.com\/blog\/connect-cursor-cline-continue-custom-api-endpoint\/\">connect Cursor, Cline and Continue<\/a> to a custom endpoint.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How a gateway exposes MCP behind one OpenAI-compatible endpoint<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In practice you hit two problems at once. Your application speaks <code>\/v1\/chat\/completions<\/code>, while MCP servers speak JSON-RPC. And you do not want one credential, base URL, and rate limit per backend.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A gateway resolves both by doing three jobs. It aggregates many MCP servers into one tool namespace, prefixing names to avoid collisions (<code>github__create_issue<\/code> versus <code>jira__create_issue<\/code>). It converts <code>tools\/list<\/code> output into the provider&#8217;s function-calling schema so any model can call them. And it presents a single OpenAI-compatible surface, so MCP-capable backends become reachable from code that only knows one request shape.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That is the role <a href=\"https:\/\/qoraapi.com\/\" target=\"_blank\" rel=\"noopener\">qoraapi.com<\/a> plays as an AI API relay: one key and one endpoint in front of many models, so the bridge below does not care which vendor answers.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Bridge MCP tools into OpenAI-compatible function calling, one gateway key.\nimport asyncio, json\nfrom openai import OpenAI\nfrom mcp import ClientSession, StdioServerParameters\nfrom mcp.client.stdio import stdio_client\n\nclient = OpenAI(base_url=\"https:\/\/qoraapi.com\/v1\", api_key=\"YOUR_KEY\")\n\ndef to_openai_tools(tools):\n    \"\"\"MCP already advertises JSON Schema; the conversion is a rename.\"\"\"\n    return [{\"type\": \"function\",\n             \"function\": {\"name\": t.name,\n                          \"description\": t.description or \"\",\n                          \"parameters\": t.inputSchema}}\n            for t in tools]\n\nasync def agent(question: str):\n    params = StdioServerParameters(command=\"python\", args=[\"server.py\"])\n    async with stdio_client(params) as (read, write):\n        async with ClientSession(read, write) as session:\n            await session.initialize()\n            mcp_tools = (await session.list_tools()).tools\n            messages = [{\"role\": \"user\", \"content\": question}]\n\n            for _ in range(5):   # bound the loop; never let an agent spin forever\n                r = client.chat.completions.create(\n                    model=\"gpt-4o\", messages=messages, tools=to_openai_tools(mcp_tools))\n                msg = r.choices[0].message\n                messages.append(msg)\n                if not msg.tool_calls:\n                    return msg.content\n                for call in msg.tool_calls:\n                    res = await session.call_tool(\n                        call.function.name, json.loads(call.function.arguments))\n                    messages.append({\"role\": \"tool\",\n                                     \"tool_call_id\": call.id,\n                                     \"content\": res.content[0].text})\n    return None\n\nprint(asyncio.run(agent(\"How many lines are in README.md?\")))\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Two production notes. Cache the tool list per session and invalidate it on <code>tools\/list_changed<\/code> rather than calling <code>tools\/list<\/code> before every turn. And bound the loop, as above \u2014 an unbounded tool-calling loop is the most common way an agent turns a bug into a bill.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Security and discovery: least privilege and capability manifests<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The security model is easy to get wrong because it is not where people look. An MCP server runs with <em>your<\/em> credentials, not the model&#8217;s. A Postgres server configured with a superuser DSN hands the model superuser. Instructions like &#8220;never delete rows&#8221; in a tool description are prompt text, not an access control.<\/p>\n\n\n\n<figure class=\"wp-block-table is-style-stripes\"><table class=\"has-fixed-layout\"><thead><tr><th>Risk<\/th><th>Where it originates<\/th><th>Control that actually works<\/th><\/tr><\/thead><tbody><tr><td>Over-privileged server<\/td><td>Server configuration and DSNs<\/td><td>Read-only database roles, allowlisted filesystem roots, scoped API tokens<\/td><\/tr><tr><td>Confused deputy<\/td><td>A server accepting and forwarding a token it was not issued<\/td><td>Validate token audience; never pass a client token upstream<\/td><\/tr><tr><td>Prompt injection via tool output<\/td><td>Untrusted content inside a tool result<\/td><td>Treat results as data, not instructions; require confirmation for destructive calls<\/td><\/tr><tr><td>Tool-name collisions<\/td><td>Aggregating several servers into one namespace<\/td><td>Namespace prefixes and per-server allowlists<\/td><\/tr><tr><td>Stale tool surface<\/td><td>Clients caching <code>tools\/list<\/code> indefinitely<\/td><td>Subscribe to <code>tools\/list_changed<\/code>; pin server versions<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Capability manifests are how you enforce the top row. Treat each server as declaring a contract: which tools exist, which annotations they carry, and which scopes the server&#8217;s own credentials need. Then let the client decide what to expose to the model at all. A useful default is to publish read-only tools automatically, require human approval for anything marked destructive, and refuse <code>openWorldHint<\/code> tools in unattended runs.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Finally, log every <code>tools\/call<\/code> with the tool name, arguments, calling user, and outcome. When a prompt injection does get through, that log is the difference between a five-minute diagnosis and a rewrite.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Frequently asked questions<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Is MCP replacing function calling?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">No. They operate at different layers and are normally used together. Function calling is how a model emits a structured call; MCP is how a tool provider advertises, transports, and authorizes that tool. An MCP server&#8217;s <code>tools\/list<\/code> output converts directly into a function-calling tool definition, so adopting MCP usually means adding a discovery layer in front of the schemas you already send.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Do I need MCP if I only have one AI app?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Only if you have more than one tool, or expect the tool surface to change. A single app calling two static internal functions is simpler with plain function calling. MCP pays off when you add a second client, add a third integration, or need runtime discovery \u2014 because at that point the alternative is editing and redeploying the host for every tool change.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Can I use MCP with a model that does not support tool calling?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Yes, for part of it. Resources and prompts involve no model-side invocation at all, so a non-tool-calling model can still consume MCP-provided context and templates. Tools are the one primitive that requires a function-calling-capable model and an execution loop in your client.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Is MCP only for local tools?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">No, though that is where it started. stdio is the simplest transport because the OS process boundary handles isolation, but Streamable HTTP serves the same protocol over the network with OAuth 2.1 tokens. The tradeoff is that remote servers need real authorization design \u2014 audience validation, per-tenant scoping, and no token passthrough \u2014 whereas local stdio servers inherit the permissions of the process that spawned them.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">MCP standardizes the interface between AI applications and the systems they touch. It does not replace function calling; it feeds it, by turning scattered per-app integrations into discoverable servers any client can reuse. The practical sequence is short: expose one read-only resource and one tool in a local stdio server, connect a client, convert <code>tools\/list<\/code> into your provider&#8217;s tool schema, then put a single OpenAI-compatible gateway in front so the model behind it is a string you can change.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Keep the credentials least-privileged, bound your agent loop, and log every tool call. Do those three things and MCP becomes what it is meant to be: plumbing you configure once instead of integrations you maintain forever.<\/p>\n\n\n\n\n<h3 class=\"wp-block-heading\">Related reading<\/h3>\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/qoraapi.com\/blog\/ai-function-calling-tool-use\/\">AI Function Calling Explained: Tools, JSON Schema, and the Tool-Use Loop<\/a><\/li><li><a href=\"https:\/\/qoraapi.com\/blog\/ai-agents-tool-use\/\">AI Agents 101: Orchestrating Multi-Step Tasks with Tool Use<\/a><\/li><li><a href=\"https:\/\/qoraapi.com\/blog\/connect-cursor-cline-continue-custom-api-endpoint\/\">How to Connect Cursor, Cline and Continue to a Custom AI API Endpoint<\/a><\/li><li><a href=\"https:\/\/qoraapi.com\/blog\/sandboxing-ai-tool-calls\/\">Sandboxing AI Tool Calls: Preventing Data Exfiltration<\/a><\/li><\/ul>\n\n","protected":false},"excerpt":{"rendered":"<p>The Model Context Protocol (MCP) is an open standard that lets any AI app connect to tools and data through one interface. Learn how it differs from function calling.<\/p>\n","protected":false},"author":1,"featured_media":109,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[5,6,9,7],"class_list":["post-110","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ai-api","tag-ai-api","tag-api-gateway","tag-developer-tools","tag-developers"],"_links":{"self":[{"href":"https:\/\/qoraapi.com\/blog\/wp-json\/wp\/v2\/posts\/110","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/qoraapi.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/qoraapi.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/qoraapi.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/qoraapi.com\/blog\/wp-json\/wp\/v2\/comments?post=110"}],"version-history":[{"count":1,"href":"https:\/\/qoraapi.com\/blog\/wp-json\/wp\/v2\/posts\/110\/revisions"}],"predecessor-version":[{"id":199,"href":"https:\/\/qoraapi.com\/blog\/wp-json\/wp\/v2\/posts\/110\/revisions\/199"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/qoraapi.com\/blog\/wp-json\/wp\/v2\/media\/109"}],"wp:attachment":[{"href":"https:\/\/qoraapi.com\/blog\/wp-json\/wp\/v2\/media?parent=110"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/qoraapi.com\/blog\/wp-json\/wp\/v2\/categories?post=110"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/qoraapi.com\/blog\/wp-json\/wp\/v2\/tags?post=110"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}