Comece com um exemplo em execução
Inicie o exemplo e adapte-o
Crie a API Orders, um banco PostgreSQL e o servidor MCP escolhido no Adios. Enviamos o código, configuramos credenciais JWT separadas e iniciamos as prévias de desenvolvimento.
Iniciar no Adios →Ainda não tem conta? Crie uma e volte a este exemplo. Escolha uma equipe e confira os recursos antes de iniciar. O exemplo completo requer um plano pago com capacidade para dois espaços e um banco de dados.
Crie passo a passo
Seguir o guia manual
Projete a API e o esquema, adicione autenticação JWT, escreva as ferramentas MCP e execute-as nos seus espaços de desenvolvimento. Cada etapa inclui código e comandos.
Seguir as etapas manuais →Explore primeiro o exemplo em execução. OAuth para login de usuários e a implantação em produção vêm depois.
Começar pela API e pelo banco de dados
Crie um servidor MCP em Python que consulte pedidos por uma API REST. Você adicionará autenticação JWT, testará o servidor em um workspace do Adios e fará o deploy.
Antes de começar, você precisa de uma API em execução e da sua chave de assinatura JWT. O guia principal inclui uma API de pedidos de exemplo com Node.js 24 e PostgreSQL, além das instruções para iniciar seu workspace de desenvolvimento.
O processo da API escuta na porta 8081 e o MCP na porta 8080 dentro dos workspaces. Os clientes usam as URLs HTTPS geradas das prévias. Mantenha API_JWT_SECRET e MCP_JWT_SECRET separados.
Crie um servidor MCP em Python
Em python/, crie um ambiente virtual e instale requirements.txt. O FastMCP gera o esquema pela assinatura da função. O handler valida o ID, chama a mesma API com HTTPX e retorna um dicionário tipado. O wrapper ASGI verifica o JWT do cliente preservando o ciclo de vida da aplicação SDK.
mcp==1.30.0
httpx==0.28.1
uvicorn==0.35.0
PyJWT==2.15.1import os
import re
import time
from urllib.parse import urlparse
import httpx
import jwt
import uvicorn
from mcp.server.fastmcp import Context, FastMCP
from mcp.server.transport_security import TransportSecuritySettings
from mcp.types import ToolAnnotations
from starlette.responses import JSONResponse
api_base = os.getenv("API_BASE_URL", "http://127.0.0.1:8081").rstrip("/")
api_secret = os.environ["API_JWT_SECRET"]
mcp_secret = os.environ["MCP_JWT_SECRET"]
if min(len(api_secret), len(mcp_secret)) < 32 or api_secret == mcp_secret:
raise ValueError("Use separate API and MCP signing secrets of at least 32 characters")
origin = os.getenv("PUBLIC_ORIGIN", "http://127.0.0.1:8080").rstrip("/")
mcp = FastMCP(
"orders-mcp", stateless_http=True, json_response=True,
transport_security=TransportSecuritySettings(
enable_dns_rebinding_protection=True,
allowed_hosts=[urlparse(origin).netloc, "127.0.0.1:8080", "localhost:8080"],
allowed_origins=[origin],
),
)
@mcp.tool(annotations=ToolAnnotations(readOnlyHint=True))
async def get_order(order_id: str, ctx: Context) -> dict[str, str]:
"""Read an order's shipping status from the Orders API."""
if not re.fullmatch(r"[a-zA-Z0-9-]{1,64}", order_id):
raise ValueError("Use an order ID containing letters, numbers, or hyphens")
# Identity comes from verified HTTP state, not a user-supplied tool argument.
subject = ctx.request_context.request.state.principal
now = int(time.time())
api_token = jwt.encode(
{"iss": "orders-demo", "aud": "orders-api", "sub": subject,
"scope": "orders:read", "iat": now, "exp": now + 300},
api_secret, algorithm="HS256",
)
try:
async with httpx.AsyncClient(timeout=5.0, follow_redirects=False) as client:
response = await client.get(
f"{api_base}/orders/{order_id}",
headers={"Authorization": f"Bearer {api_token}"},
)
response.raise_for_status()
data = response.json()
if not isinstance(data.get("id"), str) or not isinstance(data.get("status"), str):
raise ValueError("Unexpected API response")
return {"id": data["id"], "status": data["status"]}
except (httpx.HTTPError, ValueError, AttributeError):
raise ValueError("Could not read this order. Check its ID and your API access.") from None
@mcp.custom_route("/healthz", methods=["GET"])
async def health(_request):
return JSONResponse({"ok": True})
class JWTGate:
def __init__(self, application):
self.application = application
async def __call__(self, scope, receive, send):
if scope["type"] == "http" and scope["path"] == "/mcp":
headers = dict(scope["headers"])
try:
match = re.fullmatch(rb"Bearer (\S+)", headers.get(b"authorization", b""))
if not match:
raise ValueError("Missing token")
claims = jwt.decode(
match[1], mcp_secret, algorithms=["HS256"],
issuer="orders-demo", audience="orders-mcp",
options={"require": ["sub", "exp"]},
)
if not isinstance(claims["sub"], str) or not claims["sub"]:
raise ValueError("Missing subject")
if not isinstance(claims.get("scope"), str) or "orders:read" not in claims["scope"].split():
await JSONResponse({"error": "orders:read permission required"}, status_code=403)(scope, receive, send)
return
scope.setdefault("state", {})["principal"] = claims["sub"]
except (jwt.PyJWTError, ValueError):
await JSONResponse(
{"error": "Invalid or expired access token"}, status_code=401,
headers={"WWW-Authenticate": 'Bearer error="invalid_token"'},
)(scope, receive, send)
return
await self.application(scope, receive, send)
app = JWTGate(mcp.streamable_http_app())
if __name__ == "__main__":
uvicorn.run(app, host=os.getenv("HOST", "127.0.0.1"), port=int(os.getenv("PORT", "8080")))Use o import mcp.server.fastmcp do SDK oficial mostrado aqui. Este exemplo fixa a versão v1 do SDK Python MCP; pacotes com nomes semelhantes e versões principais mais recentes podem ter outras APIs de configuração e autorização.
Referência oficial: SDK Python MCP v1.
Testar em um workspace do Adios
Primeiro inicie o workspace da API do guia principal. No manifesto desta linguagem, defina API_BASE_URL com a origem da prévia da API e use os segredos de assinatura da mesma equipe de desenvolvimento.
adios ws create --name orders-mcp-dev --json
export MCP_WORKSPACE_ID=YOUR_MCP_WORKSPACE_ID
(cd python && adios sync "$MCP_WORKSPACE_ID")
adios ws run start "$MCP_WORKSPACE_ID" --wait --json
adios ws get "$MCP_WORKSPACE_ID"Copie a origem gerada da prévia MCP para PUBLIC_ORIGIN em adios.yaml. Sincronize e reinicie antes de testar: a verificação de host deve corresponder ao nome real da prévia. As sondas de integridade podem funcionar antes dessa atualização.
(cd python && adios sync "$MCP_WORKSPACE_ID")
adios ws run restart "$MCP_WORKSPACE_ID" --wait --json
export MCP_URL=https://YOUR-MCP-PREVIEW-HOST/mcp
curl --fail https://YOUR-MCP-PREVIEW-HOST/healthz
curl -i "$MCP_URL"
# Expected: 401 without a JWT.
export MCP_ACCESS_TOKEN="$(node issue-token.mjs)"
python3.13 -m venv .client-venv
.client-venv/bin/pip install -r python/requirements.txt
.client-venv/bin/python check.py
# Expected result: {'id': 'demo-1001', 'status': 'shipped'}Examinar a verificação do cliente
import asyncio
import os
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
async def main():
url = os.getenv("MCP_URL", "http://127.0.0.1:8080/mcp")
headers = {"Authorization": "Bearer " + os.environ["MCP_ACCESS_TOKEN"]}
async with streamablehttp_client(url, headers=headers) as (read, write, _):
async with ClientSession(read, write) as session:
await session.initialize()
tools = await session.list_tools()
assert any(tool.name == "get_order" for tool in tools.tools)
result = await session.call_tool("get_order", {"order_id": "demo-1001"})
assert not result.isError, result
assert result.structuredContent == {"id": "demo-1001", "status": "shipped"}, result
print("MCP initialize, tools/list, and get_order passed:", result.structuredContent)
asyncio.run(main())Teste um JWT expirado, uma audiência incorreta e a ausência do escopo orders:read. Um token de demo-client não deve conseguir ler other-1002. A API retorna 404 para o pedido desse outro tenant; o MCP retorna um erro de ferramenta.
Revise os logs de build e execução no workspace. Após alterar o código, sincronize e reinicie a prévia; este guia não pressupõe recarga automática.
adios ws run stop "$MCP_WORKSPACE_ID"Manter a verificação JWT e planejar OAuth separadamente
Esta implementação verifica JWTs emitidos pelo operador. Ela não implementa login de usuários, consentimento nem renovação. Mantenha as verificações de emissor, audiência, assinatura, expiração, escopo e tenant ao adicionar um provedor OAuth.
Para uma integração voltada aos usuários, siga os requisitos do guia principal sobre metadados do recurso, verificação de tokens e integração dos clientes. O controle de acesso do servidor de recursos JavaScript incluído é uma implementação separada; ele não ativa OAuth automaticamente neste servidor.
Use o suporte de autorização do servidor de recursos do SDK com um verificador de tokens e metadados do provedor. Transmita a identidade verificada na requisição à API.
Revisar a arquitetura OAuth compartilhadaFazer deploy deste servidor MCP no Adios
Após verificar a prévia do workspace, siga o guia principal para fazer o deploy do banco de dados e da API da versão publicada. Use os segredos de assinatura da equipe de publicação e a origem dessa API para este serviço MCP.
Fazer deploy do banco de dados e da API compartilhadosname: orders-mcp
region: de
replicas: 1
build_cmd: python -m venv .venv && .venv/bin/pip install -r requirements.txt
start_cmd: .venv/bin/python server.py
runtime:
name: python@3.13
port: 8080
health_path: /healthz
env:
HOST: 0.0.0.0
PORT: "8080"
PUBLIC_ORIGIN: https://mcp.example.com
API_BASE_URL: https://api.example.com
API_JWT_SECRET: secret://ORDERS_API_JWT_SECRET
MCP_JWT_SECRET: secret://ORDERS_MCP_JWT_SECRETNeste manifesto, substitua API_BASE_URL pela origem HTTPS da API implantada e PUBLIC_ORIGIN pela origem real do serviço MCP. Mantenha as referências aos segredos, a porta 8080 e o caminho público de verificação de integridade.
Se o nome de host padrão do MCP ainda não for conhecido, obtenha-o no primeiro deploy, atualize PUBLIC_ORIGIN e faça o deploy novamente antes de conectar um cliente. A verificação de host deve corresponder à rota real.
(cd python && adios up)
adios apps get orders-mcpadios up promotes a healthy release. It is a deployment command, not a local preview; verify the selected team and target before running it.
export MCP_ACCESS_TOKEN="$(node issue-token.mjs)"
export MCP_URL=https://YOUR-MCP-HOST/mcp
.client-venv/bin/python check.pyGere novamente o token de demonstração após 15 minutos. Confirme a chamada à ferramenta hospedada e as verificações de permissão antes de compartilhar o endpoint.
Continuar o tutorial compartilhado
Quando a chamada à ferramenta hospedada funcionar, siga o guia principal para conectar um cliente de IA, verificar permissões, examinar os logs e operar o serviço.
Conectar e operar o servidor hospedado →Explorar outra implementação
JavaScript
Use o SDK de JavaScript, esquemas de ferramentas Zod e Express. Inclui o exemplo opcional de servidor de recursos OAuth.
Abrir o guia de JavaScriptGo 1.25Go
Use o SDK de Go, structs tipadas de entrada e saída e middleware HTTP. Compile e faça o deploy de um único binário de serviço.
Abrir o guia de Go