Skip to main content
MCP (Model Context Protocol) is an open standard that lets AI agents connect to external tools through a unified interface. Instead of writing custom integrations for every API, you build an MCP server that exposes your APIs as tools, and any MCP-compatible agent can discover and use them automatically. This guide covers both sides of the MCP integration:

MCP server

There are two ways to create an MCP server:

Pro-code with FastMCP

Build a custom MCP server in Python using the FastMCP framework, starting from an OpenAPI spec or handwritten tool functions.

Click-ops with Azure APIM

Expose existing APIs provisioned in Azure APIM as MCP servers directly from the Azure Portal without writing custom code.

Pro-code MCP server with FastMCP

Build a production-ready MCP server using the FastMCP Python framework. The starter-mcp-server repository provides a working reference implementation you can clone and extend.

GitHub repository

View source code, releases, and issues

Why FastMCP?

FastMCP is the recommended way to build MCP servers in Python. The official MCP Python SDK provides a low-level protocol implementation that requires manual handler registration, hand-crafted JSON Schema dictionaries, and transport boilerplate. FastMCP removes that complexity.

Minimal boilerplate

A working MCP server is 5 lines of code. Register any Python function as a tool with a single decorator.

Automatic schema generation

Type hints become JSON Schema, Python docstrings become tool descriptions, and you don’t maintain schemas manually.

OpenAPI to MCP

Auto-generate an MCP server from any OpenAPI specification, turning every REST endpoint into an MCP tool.

Multiple transports

STDIO, Streamable HTTP, and SSE with a single configuration change.

Prerequisites

Install the following on your workstation:
  • Python 3.12+: Managed via UV
  • UV Package Manager: Modern Python package manager that replaces pip and poetry

Quick start

Run the starter MCP server on your machine:
1

Clone and install UV

2

Set up environment

3

Configure environment

Edit .env with your values:
4

Install dependencies and run

The MCP server runs at http://localhost:8557/mcp.
VPN and web proxy: if your upstream API is behind a corporate network, uncomment, and configure the proxy settings in .env. For setup instructions, see the Onboarding guide on Confluence.

Project structure

The starter-mcp-server repository contains the following directories and files:

Create an MCP server

The following sections show patterns from a minimal server through OpenAPI generation, custom tools, routing, and deployment.

Minimal example

This example registers one tool and starts the server:

Create tools with @mcp.tool

Decorate any Python function to expose it as a tool. FastMCP auto-generates the name, description, and input schema from the function signature.
Supported type annotations: ToolError messages are always sent to clients. When mask_error_details=True, FastMCP masks other exceptions from clients.

Return structured output

When a tool returns a dataclass or a Pydantic model, FastMCP automatically generates structuredContent in the MCP response, giving the calling agent a typed schema to work with instead of free-form text. The starter-mcp-server demonstrates both styles; the examples below are simplified, so see starter_mcp_server.py for the full models.

Request user input with elicitation

Elicitation lets a tool pause mid-execution to ask the user for additional information or confirmation before continuing — useful for confirmation dialogs, collecting missing inputs, or interactive workflows. The starter-mcp-server uses this in its order_product tool: it fetches a product, asks the user to confirm via a typed schema, and branches on the response. The example below is simplified — see starter_mcp_server.py for the production handler.
Elicitation requires stateful sessions, so it only works when the server runs with MCP_STATELESS_HTTP=false (or STDIO transport). With stateless HTTP there is no session to round-trip the user’s response, and the elicitation call fails. This requirement is why the starter-mcp-server defaults MCP_STATELESS_HTTP to false.

Create from an OpenAPI spec

FastMCP can auto-generate an MCP server from any OpenAPI specification. Every endpoint becomes a tool that forwards requests to the underlying API. The starter-mcp-server uses this approach with the Platzi Fake Store API.

Integrate a REST API as a tool

Instead of auto-generating from an OpenAPI spec, wrap any API call as a hand-written tool function:

Include and exclude tools

Use RouteMap to control which endpoints your MCP server exposes:
FastMCP evaluates route maps in order. The first match wins.
MCPType values:

Forward client headers

When your MCP server proxies an authenticated API, forward headers from the MCP client request to upstream API calls. The starter-mcp-server includes this pattern for forwarding Authorization headers:
Header forwarding only works with HTTP transports such as streamable-http. It doesn’t apply to STDIO transport because there is no HTTP request context.

Proxy bridge

The Proxy Provider enables transport bridging, server aggregation, and gateway patterns:

Run the server

Start the server with transport, host, port, and path options:
Transport comparison: Add a health check alongside the MCP endpoint:

Development

Use these commands while you change the server or add tools:

Run tests

Execute the test suite with pytest:

Build Docker image

Build a local image tag for the service:

CI/CD

The .github/workflows directory defines these standard workflows:
  • PR checks: Linting, testing, and validation
  • Build and publish: Docker image creation on merge
  • Release: Automated versioning and release notes
See CI/CD workflows for pipeline details.

Register in APIM via GitOps

After you deploy your FastMCP server, register it in APIM so the API gateway can route to it. This registration uses the agent-mcp-api template — a spec-only Maven project that produces an OpenAPI spec and Helm chart artifact for APIM deployment. The deployment follows the GitOps pipeline: GitHub PR → ArgoCD → Azure Service Operator (ASO) → APIM.
1

Use the agent-mcp-api template

The agent-mcp-api project defines a complete MCP Streamable HTTP API spec for APIM (POST /mcp, GET /mcp, DELETE /mcp, GET /health, GET /version) with full JSON-RPC 2.0 envelope schemas and MCP session headers.
2

Configure applications-live registration

Register entries across five files in applications-live (github.com/bb-ecos-<installation>/gc-<installation>-applications-live) under runtimes/<runtime>/apim/:
3

Set Helm values

The ArgoCD Application manifest sets these Helm parameters, and pulls shared values in through valueFiles:
apimArmId (the Azure Resource Manager ID of the target APIM instance) is required by the chart, but you don’t set it per API — it’s defined centrally in common.apim.values.yaml and pulled in through valueFiles, so every API in the installation inherits it.The path defaults to info.x-api-domain and info.x-api-service from the OpenAPI spec (joined by a slash), or the Maven artifactId if those fields are absent. Override it with the apim-helm-plugin.path Maven property at build time, or the path Helm value at deploy time — required when another API already uses the resolved path on the target APIM instance.
4

Deploy and validate

After ArgoCD picks up the merged PR, it deploys the API to APIM. Validate with a tools/list call through the APIM gateway:
For the complete reference including APIM policy configuration, product setup, and end-to-end validation details, see ADR-MCP - Track 1 - PoC Validation on Confluence.

Expose an API as an MCP server on Azure APIM

Azure APIM exposes your existing APIs as MCP servers without custom MCP server code. You select API operations in the Azure Portal, and APIM handles MCP protocol translation, tool discovery, and invocation. This approach is useful when you already have APIs provisioned in APIM and want to make them available to AI agents without building a separate FastMCP server.

Prerequisites

Before you can expose an API as an MCP server on APIM:
  1. Ensure network connectivity. The platform must have network connectivity to the target APIs. If it doesn’t, raise a ticket with the Service Desk to request access.
  2. Upload your API spec to APIM and register your API in Azure APIM using applications-live (github.com/bb-ecos-<installation>/gc-<installation>-applications-live under runtimes/<runtime>/apim).

High-level steps

Configure MCP in APIM through the portal:
  1. Navigate to APIs → MCP Servers (Preview) in your APIM instance
  2. Click Create MCP Server → Expose an API as an MCP Server
  3. Select the API and operations to expose, starting with read-only endpoints
  4. Configure APIM policies for security, including subscription key validation, rate limiting, and audit logging
  5. Test with MCP Inspector or curl
Known limitation: POST operations with requestBody.content sections in the OpenAPI spec cause /tools/list to hang indefinitely. Remove or simplify the requestBody.content section in your OpenAPI spec before you expose the API via MCP. See the full guide for details.
For complete click-ops instructions that cover APIM policies, security configuration, rate limiting, audit logging, external MCP server proxying, and known issues, see the APIM MCP: click-ops guide on Confluence.

MCP client

Connect to an MCP server from different types of clients, including programmatic Python clients, AI-native tools like Cursor and Claude Desktop, and AI agent frameworks like Agno.

GitHub repository

View source code, releases, and issues
You need a running MCP server to connect to. See MCP server to create one.

Transport types

Before connecting, determine which transport your MCP server uses:
SSE transport is deprecated by MCP. Always use Streamable HTTP for deployments. Use STDIO only for local development or CLI-based MCP servers such as npx and uvx packages.

FastMCP client

FastMCP provides a built-in Client class for connecting to any MCP server programmatically. The client infers the transport from what you pass to it.

Cursor IDE

Cursor has built-in MCP support (v0.40+). Create .cursor/mcp.json in your project root:
Restart Cursor after adding the configuration. MCP servers only load at startup.

Claude Desktop

Claude Desktop reads its MCP configuration from claude_desktop_config.json:

Agno agent

Agno is a Python framework for building AI agents with built-in MCP support through its MCPTools class.

Pass headers to MCP servers

How you pass authentication headers depends on your client type:

Next steps

From here you can extend agents, teams, knowledge, and pipelines: