Agent77

MCP Server Requirements

Your MCP (Model Context Protocol) server is where the agent's tools live. Agent77 connects to it over SSE and forwards the user's JWT so your server can authorize every request.

What Your MCP Server Needs

  • SSE transport. Agent77 connects via Server-Sent Events. Your server must support the MCP SSE transport layer.
  • JWT validation. Every request includes the user's JWT in the Authorization: Bearer header. Validate it before executing any tool.
  • Tool definitions. Expose tools using the MCP tools/list method. Each tool needs a name, description, and JSON Schema for its parameters.

JWT Validation

When Agent77 calls your MCP server, it forwards the JWT that was issued by your token endpoint. Your server should:

  1. Extract the token from the Authorization header.
  2. Fetch your JWKS (or cache it) and verify the signature.
  3. Check aud === "chatbot" and iss matches your domain.
  4. Check exp has not passed.
  5. Use sub as the authenticated user ID for authorization.

Python Example

import jwt
import requests
from functools import lru_cache

ISSUER = "https://app.example.com"
JWKS_URL = f"{ISSUER}/.well-known/jwks.json"

@lru_cache(maxsize=1)
def get_jwks():
    return requests.get(JWKS_URL).json()

def validate_token(auth_header: str) -> dict:
    """Validate JWT and return decoded claims."""
    token = auth_header.removeprefix("Bearer ").strip()
    jwks = get_jwks()

    # Decode header to find kid
    header = jwt.get_unverified_header(token)
    kid = header["kid"]

    # Find matching key
    key_data = next(k for k in jwks["keys"] if k["kid"] == kid)
    public_key = jwt.algorithms.RSAAlgorithm.from_jwk(key_data)

    return jwt.decode(
        token,
        public_key,
        algorithms=["RS256"],
        audience="chatbot",
        issuer=ISSUER,
    )

Node.js Example

const jwt = require("jsonwebtoken");
const jwksClient = require("jwks-rsa");

const ISSUER = process.env.SITE_URL;

const client = jwksClient({
  jwksUri: `${ISSUER}/.well-known/jwks.json`,
  cache: true,
  rateLimit: true,
});

async function validateToken(authHeader) {
  const token = authHeader.replace("Bearer ", "").trim();
  const decoded = jwt.decode(token, { complete: true });
  const key = await client.getSigningKey(decoded.header.kid);

  return jwt.verify(token, key.getPublicKey(), {
    algorithms: ["RS256"],
    audience: "chatbot",
    issuer: ISSUER,
  });
}

Tool Definition Best Practices

  • Clear descriptions. The agent reads tool descriptions to decide when to use them. Write them as if explaining to a coworker.
  • Specific parameter schemas. Use enum for known values, add description to each property, and mark required fields.
  • Scoped permissions. Use the JWT sub claim to scope data access. A tool like list_orders should only return orders for the authenticated user.
  • Return structured data. Return JSON objects rather than strings so the agent can reason about the result.
  • Fail with context. When a tool call fails, return an error message that helps the agent recover: {"error": "Order not found", "suggestion": "Try list_orders first"}

Example Tool Definition

{
  "name": "get_order",
  "description": "Retrieve details of a specific order for the current user. Returns order status, items, and tracking info.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "order_id": {
        "type": "string",
        "description": "The order ID (e.g. ORD-12345)"
      }
    },
    "required": ["order_id"]
  }
}