DeepInfra raises $107M Series B to scale the inference cloud — read the announcement

MCP Servers Explained: A Practical Guide for Developers
Published on 2026.09.16 by DeepInfra
MCP Servers Explained: A Practical Guide for Developers

Giving an AI application access to a database, API, file system, or internal service sounds simple until you have to maintain the integration. You need to define what the model can access, describe operations, execute requests safely, return structured results, and handle authentication. You may need to repeat much of that work when another AI application needs the same capability.

The Model Context Protocol (MCP) standardizes that connection. You can expose tools and context through an MCP server and let compatible applications discover and use them through the same protocol.

To ship a useful MCP server, you need to understand where it sits in the application stack, what it should expose, how clients connect to it, and which design decisions matter when the integration leaves the local prototype.

In this article, we’ll explain how MCP servers work, how to choose between tools, resources, and prompts, and what you need to consider when moving an MCP server into production.

What Does an MCP Server Actually Do?

An MCP server is the boundary between an AI application and the systems you want that application to use. MCP follows a host-client-server architecture.

  • MCP host: The AI application coordinating the interaction.
  • MCP client: The component inside the host that connects to one MCP server.
  • MCP server: The program that exposes context and capabilities to that client.

A single host can connect to multiple servers. It creates a separate MCP client for each connection to keep server boundaries independent. For example, a coding agent might connect to one server for source control, another for issue tracking, and another for internal documentation.

MCP also separates a data layer and a transport layer. The data layer defines protocol messages, capability discovery, tools, resources, prompts, and related behavior. The transport layer determines how those messages move between client and server. So, the same server capabilities can be exposed locally through standard I/O or remotely over HTTP.

Here is a minimal code example using FastMCP to create one MCP tool, discover that tool through an MCP client, pass its schema to a DeepInfra-hosted model, and route the model’s tool call back through the MCP server.

Install FastMCP for the MCP server and client, and the OpenAI SDK for DeepInfra’s OpenAI-compatible API:

“`

pip install fastmcp openai
copy

“`

Import the dependencies and create a FastMCP server. The @mcp.tool() decorator exposes get_weather as an MCP tool and derives its input schema from the Python function. 

“`

import asyncio
import json
import os
from fastmcp import FastMCP, Client
from openai import OpenAI


mcp = FastMCP("WeatherServer")




@mcp.tool()
def get_weather(city: str) -> str:
    """Get current weather for a city."""
    weather_db = {
        "london":   "Overcast, 14C, humidity 78%",
        "tokyo":    "Partly cloudy, 28C, humidity 65%",
        "new york": "Clear sky, 22C, humidity 45%",
        "paris":    "Light rain, 16C, humidity 82%",
        "dubai":    "Sunny, 42C, humidity 20%",
    }
    return weather_db.get(
        city.lower(),
        f"No data for '{city}'. Try: {', '.join(weather_db.keys())}",
    )
copy

“`

Create an MCP client and use list_tools() to discover the capabilities exposed by the server. The discovered MCP schema is then converted into the OpenAI-compatible tool format that the model expects. 

“`

client = Client(mcp)


async def discover_tools() -> list[dict]:
    async with client:
        mcp_tools = await client.list_tools()
        return [
            {
                "type": "function",
                "function": {
                    "name":        t.name,
                    "description": t.description or "",
                    "parameters":  t.inputSchema,
                },
            }
            for t in mcp_tools
        ]
copy

“`

Configure the OpenAI client to use DeepInfra’s OpenAI-compatible endpoint. The model receives the discovered tools and can use tool calling to select one and generate its arguments. 

“`

DEEPINFRA_API_KEY = os.getenv("DEEPINFRA_API_KEY", "your_api_key_here")


llm = OpenAI(
    api_key=DEEPINFRA_API_KEY,
    base_url="https://api.deepinfra.com/v1/openai",
)


MODEL = "zai-org/GLM-5.2"


async def agent(user_message: str, tools: list[dict]) -> str:
    messages = [
        {"role": "system", "content": "You are a helpful weather assistant. Use the provided tools to answer questions. Be concise."},
        {"role": "user", "content": user_message},
    ]


    async with client:
        while True:
            response = llm.chat.completions.create(
                model=MODEL,
                messages=messages,
                tools=tools,
                tool_choice="auto",
            )
            assistant_msg = response.choices[0].message
            messages.append(assistant_msg)


            if not assistant_msg.tool_calls:
                return assistant_msg.content


            for tc in assistant_msg.tool_calls:
                tool_name = tc.function.name
                tool_args = json.loads(tc.function.arguments)
                result = await client.call_tool(tool_name, tool_args)


                result_text = ""
                if hasattr(result, "content"):
                    result_text = "\n".join(
                        c.text for c in result.content if hasattr(c, "text")
                    )
                else:
                    result_text = str(result)


                messages.append({
                    "role": "tool",
                    "tool_call_id": tc.id,
                    "content": result_text,
                })
copy

“`

When the model returns a tool call, client.call_tool() routes it to the MCP server for execution. The result is added to the conversation with the matching tool_call_id, allowing the model to use it in the next inference step and either make another tool call or return the final answer.

Finally, discover the available tools and send a request that requires the model to use one of them. asyncio.run() starts the asynchronous MCP workflow. 

“`

async def main():
    tools = await discover_tools()


    queries = [
        "What's the weather like in Tokyo?",
        "Compare the weather in London and New York. Which city is warmer?",
    ]


    for q in queries:
        print(f"Q: {q}")
        answer = await agent(q, tools)
        print(f"A: {answer}\n")




if __name__ == "__main__":
    asyncio.run(main())
copy

“`

Tools, Resources, and Prompts: What Should Your Server Expose?

An MCP server exposes three primary server-side primitives, each with a different control model. Tools are model-controlled, resources are application-controlled, and prompts are user-controlled.

Tools: when the AI needs to do something

MCP tools are callable operations that the model can invoke to serve user requests and context. They are appropriate when the model needs to take an action or perform a computation, such as querying a database, retrieving an order, creating an issue, or calling an existing API operation.

Each tool specifies the available operation and the inputs it accepts through an input schema. When the model chooses a tool, the MCP client sends the request to the server, which executes the operation and returns the result.

Resources: when the AI needs context

Resources expose information that an AI application can access and share with the model as context. The host decides which available resources to retrieve and how to include their contents in the model’s context

MCP identifies resources through URIs (Uniform Resource Identifiers), allowing the server to expose data from different underlying sources such as a database through a consistent interface.

Prompts: when you want reusable interaction patterns

Prompts are reusable templates for interactions that users can explicitly select, such as reviewing a code change or analyzing an incident. A prompt can define the messages to send to the model and accept arguments needed to customize the interaction.

The MCP server defines the prompt, the client makes it available to the user, and the server returns the completed messages when the user invokes it.

MCP Server vs. API vs. Function Calling: What Is Actually Different?

MCP server, APIs, and function calling can all be involved in the same request, but each serves a different purpose.

  • An API defines how software interacts with a service. If your CRM already exposes an endpoint for retrieving an account, MCP does not make that endpoint unnecessary.
  • An MCP server can sit in front of those APIs and expose selected operations using an interface MCP clients understand. The underlying API remains responsible for its actual business logic.
  • Function calling operates closer to the model. The model receives tool definitions, determines whether an operation is required, and produces a tool call with arguments. The application executes the requested operation and returns the result to the model.

Here’s what each layer controls in the request:

LayerWhat it definesRole in the request
Function callingWhich tools the model can request and their argument schemasLets the model select an operation and generate its arguments
MCP serverWhich external capabilities are exposed through MCPMakes tools and context discoverable and accessible to MCP clients
APIThe service’s endpoints and application contractExecutes or provides access to the underlying application functionality

Local or Remote? Choose How the MCP Server Will Run

MCP defines two standard transports, STDIO and Streamable HTTP, which carry the same protocol semantics but create different operating models.

Local MCP server: STDIO

The MCP client launches the server as a subprocess with STDIO and exchanges newline-delimited JSON-RPC messages through standard input and output. The server reads protocol messages from stdin, writes protocol messages to stdout, and can use stderr for diagnostics. Anything written to stdout that is not a valid MCP message can break the protocol stream.

STDIO also keeps the deployment boundary small. There is no remote endpoint, TLS termination, multi-tenant routing, or network authorization layer to operate before you can prove the capability works.

This model works well for local filesystem and source-code operations, developer or desktop tooling, and workflows that need access to locally available credentials or processes.

STDIO transport lets an MCP client launch a local server process and exchange messages through standard input and output.

Remote MCP server: Streamable HTTP

With Streamable HTTP, the MCP server runs independently and can serve multiple clients. In the current protocol, clients send messages as HTTP POST requests to a single MCP endpoint. Responses can return as JSON or through a request-scoped Server-Sent Events (SSE) stream when streaming is needed.

This makes Streamable HTTP better suited to shared services, SaaS integrations, and production deployments. The trade-off is that you now need to handle standard service concerns such as authentication, authorization, rate limiting, tenant isolation, and monitoring.

For protected HTTP servers, MCP defines an OAuth-based authorization model in which access tokens are validated for the intended MCP resource. 

What Breaks When an MCP Server Moves Beyond the Demo?

A demo shows that a server can provide a capability and return a result. In production, reliability depends on the model choosing appropriate tools, permissions limiting actions, failures being recoverable, and the execution process being observable.

  • Too many tools make selection less reliable. Every tool definition adds to the model’s decision space and input context. Model quality can degrade as more functions are supplied, and function definitions also count toward input token usage. Keep the available toolset focused on the capabilities required for the workflow, rather than exposing every backend endpoint.
  • Ambiguous tool contracts cause incorrect calls. Similar tools such as search_user and find_user become difficult to distinguish unless their purpose is explicit. Use distinct names, descriptions, and input schemas so the model can determine which operation applies and generate valid arguments.
  • Authentication alone does not control actions. A valid caller should not automatically have permission to invoke every tool. Use least-privilege scopes so clients request only the permissions required for an operation, and add confirmation or policy gates before destructive or high-impact actions.
  • Generic errors prevent recovery. MCP distinguishes protocol failures from tool execution errors. Return specific errors for invalid arguments, authorization failures, upstream failures, or business-rule violations so the model can determine whether and how to retry.
  • API-level monitoring does not explain agent failures. Trace the path from the model’s decision to the tool request, MCP execution, and then to the upstream service and the tool’s output. Capture the tool name, latency, execution status, authorization failures, and retries to identify whether a failure originated from model selection, the MCP server, or the underlying service.

When Should You Use MCP and When Is It Overkill?

MCP is valuable when the capability boundary itself needs to become reusable.

If multiple AI hosts require the same integration or if capabilities should be easily discoverable rather than embedded into a single application, an MCP server provides a stable integration surface. Additionally, it allows you to change models and agent frameworks without needing to rebuild access to your internal systems.

It is less compelling when one application owns both sides of a small, static workflow. If an agent needs one private API operation and no other client will reuse it, ordinary function calling may remain simpler.

A useful test is whether you are standardizing a reusable integration or wrapping a single function in another protocol.

Where DeepInfra Fits in an MCP Stack

MCP provides standardized access to tools and context, while the model decides which tool to call, what arguments to send, and how to use the result.

DeepInfra provides that inference layer through its OpenAI-compatible API. Its supported models can use tool calling to select a function and generate structured arguments. The application invokes the requested tool through the MCP server, returns the result to the model, and runs the next inference step to continue or complete the task. DeepInfra supports automatic tool selection, single tool calls, and parallel tool calls, although parallel-call quality can vary by model.

Because the MCP integration remains separate from inference, you can compare different models for tool-calling reliability, latency, context window, and inference cost without changing the MCP server or its backend integrations. DeepInfra currently provides 100+ open-source models through its inference platform.

Conclusion

Shipping an MCP server starts with the capability boundary. Decide what the model should be able to do, what the application only needs to read, and whether reusable prompts add value. Keep tools focused and schemas clear. 

Use STDIO for local workflows and switch to Streamable HTTP when serving as shared infrastructure. Before production, treat authorization, error semantics, observability, and tool selection behavior as part of the interface. 

Moreover, keep MCP focused on standardizing access to external capabilities while existing services retain business logic. This separation also lets the inference layer evolve without reworking the MCP integration.

Explore DeepInfra’s open-weight models to find the right model for tool calling, MCP-powered applications, and agentic workflows. For any questions reach out to us at info@deepinfra.com.  You can also join the community on Discord, or find us on X at @DeepInfra

Related articles
DeepSeek V4 Pro Pricing Guide 2026: Pricing, Providers & Cost ComparisonDeepSeek V4 Pro Pricing Guide 2026: Pricing, Providers & Cost Comparison<p>DeepSeek V4 Pro matters because it pushes two levers developers actually care about at the same time: open-weight availability and a very competitive provider market. As of the research here, DeepSeek V4 Pro Max is tracked across six API providers, and five of them cluster at the same blended price of $2.17 per 1M tokens [&hellip;]</p>
Why Your API Bill Doubled Without Changing ModelsWhy Your API Bill Doubled Without Changing Models<p>You deployed a reasoning model, ran it for a week, and got a billing email that was twice what you expected. You didn&#8217;t change the model. You didn&#8217;t change the prompt. You didn&#8217;t add more users. The only thing that changed is that the model started thinking harder and that thinking costs money you can&#8217;t [&hellip;]</p>
Kimi K3 vs Claude Opus 4.8 vs GPT-5.6 Sol: Practical AI Model ComparisonKimi K3 vs Claude Opus 4.8 vs GPT-5.6 Sol: Practical AI Model Comparison<p>The three strongest models available on DeepInfra right now don&#8217;t separate cleanly by capability tier. Kimi K3 (available via DeepInfra), Claude Opus 4.8, and GPT-5.6 Sol all score within 3 points of each other on the Artificial Analysis Intelligence Index. All three support one-million-token context windows. All three handle vision. And yet the right choice [&hellip;]</p>