SmartGateSmartGate

What Is MCP Model Context Protocol? Naming and Abbreviations

MCP stands for Model Context Protocol, and the two spellings do different jobs: the acronym names the wire protocol and its specification, while the full phrase appears in page titles, vendor announcements and product names. The name says the protocol carries context between a model and a server.

Short answer: MCP stands for Model Context Protocol, and the two spellings do different jobs: the acronym names the wire protocol and its specification, while the full phrase appears in page titles, vendor announcements and product names. The name says the protocol carries context between a model and a server. It says nothing about who may call, what a call costs, or what gets logged, and those are the three questions the name quietly leaves to whoever deploys it.

Key takeaways

  • One protocol, two spellings, no contradiction. MCP is not a different thing from the Model Context Protocol; it is the short form, and the specification uses both.
  • The short form wins wherever a machine reads it. Method names, configuration keys, audit labels and package names compress to three letters, because a person types them and code parses them.
  • The long form wins at first mention. A title, an announcement or a product page expands the acronym once, then shortens — which is why the phrase feels official and the acronym feels technical.
  • The name is descriptive and non-binding. It describes what travels; it does not constrain the transport, the message format or the host, which is what lets the protocol outlive its own details.
  • A rename is a migration. Where a name has to change, the cost is every stored string that already used it, and that is the reason stable names outlive accurate ones.

A naming benchmark: one constant every caller agrees on

Names are cheap to invent and expensive to change, so the smallest useful benchmark is a name that exists in exactly one place. This function returns a session cookie name from a single definition rather than spelling the string out at every call site.

# lib/team.ts — source lines 103–105 (getTeamCookieName)
function getTeamCookieName() {
  return "sg_team";
}

Four lines, one decision, and the property worth copying is that no caller owns the literal. When the name has to change it changes in one file, and a reader who greps for the string finds the definition instead of forty copies of it. The acronym works the same way. MCP is defined once, in the specification, and every document, endpoint and tool list refers back to that definition rather than to a local paraphrase. A name that lives in more than one place is a name that will eventually disagree with itself, and the disagreement surfaces at the worst moment — a cookie a browser refuses to send, or a configuration key a client silently ignores. the MCP cluster hub keeps the definitions for this topic in one place for the same reason.

The implementation behind a display name: Free, Pro, Teams, Enterprise

An internal identifier and the name a person reads are two different things, and treating them as one is how a rename becomes a migration. This function is the entire mapping layer between them: a stored plan value on one side, a display string on the other.

# lib/billing/plan-display-name.ts — source lines 3–8 (planDisplayName)
function planDisplayName(plan: Plan): string {
  if (plan === "PRO") return "Pro";
  if (plan === "TEAMS") return "Teams";
  if (plan === "ENTERPRISE") return "Enterprise";
  return "Free";
}

Four branches and a default, and every interesting property is in that default. The stored value is an uppercase token — the identifier that appears in entitlements, webhooks and stored records — while Free, Pro, Teams and Enterprise are labels a person reads on a pricing page. Nothing downstream needs to know the spelling of a label, and no label ever reaches a stored record. The same split makes the two MCP spellings safe to interchange in prose: the acronym is the identifier, the full phrase is the display name, and no part of the specification asks a client to parse either. how the acronym works takes that argument down to the mechanism underneath it.

The same name on a gateway pricing page and in an error string

A name drifts fastest outside the specification that defines it. A pricing page compresses, because it has to fit a table; a documentation page expands, because it has to explain; an error string compresses again, because it has to fit one line. A gateway sitting in front of a protocol inherits all three habits at once, and the result is a product where one operation is called three things depending on where a person is standing.

The direction of the drift is the useful part. Machine-facing text — configuration keys, error codes, audit labels, log columns — compresses to the acronym, because those strings are typed by hand and parsed by code. Human-facing text expands the acronym at first mention and shortens afterwards. So the failure to watch for is not inconsistency in prose; it is a mixed spelling inside a machine-facing key, where a client pastes one form and the server expects the other. The fix is boring. Choose the short form once for anything a client will type, and let prose do whatever reads best.

Cloudflare-side names: a class that keeps the name it replaces

Choosing a name is also choosing a migration, and the cheapest migration is the one where nothing is renamed at all. This class keeps the name of the thing it stands in for, and says so in its own docstring.

# backend/smartgate/modules/search/algorithm.py — source lines 83–99 (SearchQuery)
class SearchQuery:
    """搜索查询 — 替代 searx.search.models.SearchQuery。"""

    def __init__(
        self,
        query: str,
        engines: Optional[list[str]] = None,
        lang: str = "en",
        pageno: int = 1,
        max_results: int = 10,
    ):
        self.query = query
        self.engines = engines
        self.lang = lang
        self.pageno = max(1, pageno)
        self.max_results = max(1, min(max_results, 100))
        self.timeout_limit = None

The replacement is a different implementation behind the same name, which is exactly why no caller has to change anything. Fields are normalised on the way in — a page number is forced to at least one, a result count is clamped into a range — so the name keeps the old contract while the body enforces a better one. Hosted documentation behaves the same way: while a specification keeps a stable address, the content underneath can be revised as often as it likes. That is the property to ask about when a vendor announces a rename. Does the old name still resolve? If it does not, the rename is a migration and it needs a budget. The page where the name is written down is the one to read before pinning either a name or a revision to a deployment.

A name inside larger systems: memory, versioned

Once a name has to live inside a system that reports on itself, the name becomes data rather than prose. This module declares its own identity before it declares any behaviour, and it declares a version next to the name.

# backend/smartgate/modules/memory/__init__.py — source lines 73–100 (MemoryModule)
class MemoryModule(SmartModule):
    """记忆管理模块 — 包装 Mem0 Memory 核心类,支持 LLM 降级。"""

    name = "memory"
    version = "0.2.1"
    description = "智能记忆管理 (Mem0: 实体提取 + 多信号检索 + LLM 降级)"
    dependencies = []

    MEMORY_OP_TIMEOUT_S = 45.0

    def __init__(self):
        self._memory = None
        self._resources = None
        self._compensator = None
        self._llm_available = True
        self._health_task = None
        self._write_lock = asyncio.Lock()

    async def _run_memory_op(self, fn, *args, **kwargs):
        try:
            return await asyncio.wait_for(
                asyncio.to_thread(fn, *args, **kwargs),
                timeout=self.MEMORY_OP_TIMEOUT_S,
            )
        except asyncio.TimeoutError as exc:
            raise TimeoutError(
                f"memory operation timed out after {self.MEMORY_OP_TIMEOUT_S:.0f}s"
            ) from exc

Note what the declared name is not. It is a short lowercase token that a registry can key on and a log can print, not a sentence a person reads; the descriptive text sits in a separate attribute, and the version in a third one, so the name can stay stable while the description and the version move independently. That separation is why a protocol can keep three letters for years without anyone having to agree on what the expanded words imply, and why a client can record the name of a capability without recording a marketing sentence beside it. A system that publishes its own name gets one free property: a registry entry, a health endpoint and an audit row can all refer to the same thing with no translation step in between. Where that stable name meets a dated revision is revision history and transports.

Meta-evolution of a name: route path, handler, audit label

One operation tends to acquire three names, and they evolve at different speeds. This handler is a good specimen because all three are visible inside a single function: the route path a caller posts to, the function name a maintainer greps for, and the label that ends up in the audit row.

# backend/smartgate/api/v1/memory.py — source lines 90–109 (handle_memory_delete)
@router.post("/api/v1/memory/delete", response_model=SmartGateResponse)
async def handle_memory_delete(req: MemoryRequest, request: Request):
    registry = request.app.state.registry
    audit_hook = request.app.state.audit_hook
    ctx = ToolContext(team_id=team_id_from_request(request))

    start = time.perf_counter()
    result = await registry.get("memory").process(
        ctx, action="delete", memory_id=req.memory_id, user_id=req.user_id,
    )
    elapsed_ms = (time.perf_counter() - start) * 1000

    await audit_hook(ctx, result, "memory_delete", params={"memory_id": req.memory_id})

    return SmartGateResponse(
        success=result.success,
        data=result.data,
        error={"code": "ERROR", "message": result.error} if not result.success else None,
        meta={**(result.meta or {}), "processing_time_ms": round(elapsed_ms, 2)},
    )

The audit label is the interesting one, because it is the only name built to outlive a refactor. The path can gain a prefix and the handler can be renamed, while the label survives in a log table that already holds rows under it — so it stops being a description and becomes an identifier, in the same way a retired transport name survives in a metrics column long after the transport itself is gone. A protocol ends up with the same three layers, and they are worth keeping apart: the method name on the wire, the capability name exchanged during the handshake, and the label a host shows a person. The set of names a host is allowed to call is published in the tools list reference, which is the closest thing to a public interface a server has.

Framework names hidden behind one verb: convert

A name can also hide work. This method is called convert and performs none of the conversion itself: it delegates to two libraries in sequence, and its name says nothing about which two.

# backend/smartgate/modules/fetch/html_converter.py — source lines 82–97 (convert)
def convert(self, html: str) -> str:
        from markdownify import markdownify as md

        # Step 1: markdownify 基础转换
        result = md(
            html,
            heading_style="ATX",
            bullets="-",
            code_language="",
            strip=["script", "style", "nav", "footer", "aside"],
        )

        # Step 2: GFM 后处理
        result = self.gfm.process(result)

        return result.strip()

That is not a defect, and it is worth seeing why. The caller wanted a document turned into markdown, not a decision about which markdown library wins, so the framework names belong in the body rather than in the signature, and swapping a library stays a one-line change. The cost is discoverability: a reader who searches for the library finds this method only through its imports. MCP makes the same trade at a much larger scale. The name of the protocol does not name the transport, the message format or the host, because those are choices each implementation makes, and naming any of them in the protocol would have forced a rename each time one changed. Which implementation you run is a separate question, and building an MCP server is the page that answers it.

Names on paper and names on the wire: the operator map

Two systems rarely name the same operation the same way, and the fix is a translation table rather than a compromise. This helper takes a filter written in one vocabulary, rewrites it into a neutral one, and refuses anything it does not recognise.

# backend/smartgate/modules/memory/algorithm.py — source lines 1251–1272 (Memory.process_condition)
def process_condition(key: str, condition: Any) -> Dict[str, Any]:
            if not isinstance(condition, dict):
                # Simple equality: {"key": "value"}
                if condition == "*":
                    # Wildcard: match everything for this field (implementation depends on vector store)
                    return {key: "*"}
                return {key: condition}

            result = {}
            for operator, value in condition.items():
                # Map platform operators to universal format that can be translated by each vector store
                operator_map = {
                    "eq": "eq", "ne": "ne", "gt": "gt", "gte": "gte",
                    "lt": "lt", "lte": "lte", "in": "in", "nin": "nin",
                    "contains": "contains", "icontains": "icontains"
                }

                if operator in operator_map:
                    result.setdefault(key, {})[operator_map[operator]] = value
                else:
                    raise ValueError(f"Unsupported metadata filter operator: {operator}")
            return result

Read it as a policy about names. Every operator allowed through is listed explicitly, and an unknown name raises instead of passing through untouched, which is what keeps a typo from quietly becoming a filter that matches everything. The map also shows the honest limit of any translation layer: it can only promise the operators both sides already share, and a wildcard is carried through as a marker rather than interpreted, because interpreting it depends on the store underneath. Write the map down whenever you name one thing in two places — a protocol and a product, a paper and a wire format. The comparison that decides whether two protocols need a map at all is MCP versus A2A, and the naming is the least reliable part of that answer.

How SmartGate compares

The naming question has a practical edge: which spelling do you put in a key, a log line and a support article, and which one do you let prose handle.

What the name says Who actually reads it What it commits you to
MCP three letters, no expansion clients, configuration files, log columns, package names nothing but a reference to the specification
Model Context Protocol what travels between a model and a server titles, announcements, first mentions in prose an explanation, and the room to give one
A vendor product name who is selling it pricing pages, sales conversations whatever that vendor's implementation does
SmartGate a hosted endpoint, not a protocol the configuration file on one machine a key per caller, a limit and an audit row per call

The useful reading is that only the first row is a stable identifier. Everything below it is a label that can change without the protocol changing, which is why a client should be configured with the short form and why prose can afford to expand it. what an MCP gateway does is where the naming stops mattering and the operational questions start, and the free tier carries 2 million tokens a month across all seven tools with no card required.

How to get started

  1. Write the acronym once, in your own documentation. Expand it at first mention and use the short form afterwards; readers who arrived from a search for either spelling will find the page.
  2. Use the short form in every key, header and label. Anything a person pastes into a configuration file should be the three-letter form, and it should be the same three letters everywhere.
  3. Check the name against the capability, not the marketing copy. A server that calls itself MCP compatible still has to declare its capabilities during the handshake, and that list is the honest one. auth for MCP traffic covers what happens next, once more than one caller shares the endpoint.
  4. Read the revision, not the name. The wire behaviour is dated; the name is not. Log the revision beside each request so a behaviour change is attributable.
  5. Keep a list of the names you have already shipped. A renamed key that clients still send is a permanent part of your interface, whatever the current documentation says.

Start on the free tier — 2 million tokens a month and all seven tools — at start free; the endpoint shape is in the product documentation and the plan limits are on the pricing page.

Frequently Asked Questions

Limitations and what this does not do

  • This page is about naming, not about the protocol. The messages, the handshake and the transports are documented elsewhere in the cluster; here they appear only where a naming decision shaped them.
  • The name will outlive some of its accuracy. A descriptive name is a snapshot of how a project was understood on the day it was chosen. Reading it as a specification is the mistake this page exists to prevent.
  • One of eight sections carries no code. The section on pricing pages and error strings matched no unique symbol, so it is written from the specification and from vendor pages, with no quoted implementation, as the abstain rule requires.
  • The quoted code comes from one product. The excerpts illustrate how names are stored, displayed, translated and logged in a real codebase; they are not a naming standard anyone else has to adopt.
  • The spelling on a vendor page is not a statement of scope. Anthropic's MCP clients are one important client family, and a product that borrows the acronym has borrowed a name, not a compatibility guarantee.

Sources

Method note

Every fenced block on this page was cut out of a slice body returned by the slice API and then re-asserted byte-for-byte as a substring of that body before rendering; the first line inside each fence records the source file and the exact lines it came from. Symbols were pinned by whole-name containment and confirmed by the service's slot-proof endpoint — seven of the eight planned sections pinned, no abstentions. The one section without a fence matched no unique symbol, so it is argued from the published specification and from the vendors' own pages instead. The memory module excerpt is a window over its declaration block rather than the whole symbol: the naming argument rests on the declared name, description and version, and the remaining lines describe behaviour that this page does not claim. No code here was typed by hand, and no third-party client implementation is quoted.

Slice provenance

# SERP keyword Symbol File Source lines How it was pinned sha256(12)
1 agent memory benchmark getTeamCookieName lib/team.ts 103–105 rule A L2 → slot-proof 7f69129c5c9f
2 agentic rag implementation planDisplayName lib/billing/plan-display-name.ts 3–8 rule A L2 → slot-proof 2d1944181319
3 cloudflare ai gateway models SearchQuery backend/smartgate/modules/search/algorithm.py 83–99 rule A L2 → slot-proof 34b8874f295d
4 llm agent memory systems MemoryModule backend/smartgate/modules/memory/__init__.py 73–100 rule A L2 → slot-proof fde2ba3b5f23
5 memevolve: meta-evolution of agent memory systems handle_memory_delete backend/smartgate/api/v1/memory.py 90–109 rule A L2 → slot-proof 3f9f02f5f941
6 agent memory framework convert backend/smartgate/modules/fetch/html_converter.py 82–97 rule A L2 → slot-proof d858200a75c5
7 agent memory paper Memory.process_condition backend/smartgate/modules/memory/algorithm.py 1251–1272 rule A L2 → slot-proof d3bca8321492

Every fence above was cut from a slice body and re-asserted against it byte-for-byte before this page was rendered. 7 of 8 sections pinned, 0 abstentions, 1 misses.