Skip to content

Anthropic Registry API Test Commands

Note: The Anthropic API version is defined in registry/constants.py as ANTHROPIC_API_VERSION for easy version management.

Overview

This document provides comprehensive curl commands to test all three endpoints of the Anthropic Registry API v0.1 implementation:

  1. GET /v0.1/servers - List all MCP servers with pagination
  2. GET /v0.1/servers/{serverName}/versions - List versions for a specific server
  3. GET /v0.1/servers/{serverName}/versions/{version} - Get detailed info for a specific version

Prerequisites

1. Start the MCP Gateway Registry

# Build and start all services
./build_and_run.sh

# Wait for services to be ready (check logs)
docker compose logs -f registry

2. Authentication Setup

The v0.1 API requires JWT authentication via Keycloak.

Generate Fresh Token (Required)

The ingress token expires regularly, so you must generate a new one before testing:

# Step 1: Generate fresh Keycloak credentials
credentials-provider/generate_creds.sh

# Step 2: Load the token from ingress.json
export TOKEN=$(jq -r '.access_token' .oauth-tokens/ingress.json)

# Step 3: Verify token was loaded
echo "Token loaded: ${TOKEN:0:50}..."

Important Notes:

  • Tokens expire after 5 minutes - if you get authentication errors, regenerate with ./credentials-provider/generate_creds.sh
  • The generate_creds.sh script creates a new M2M token in .oauth-tokens/ingress.json
  • This token has full access to all MCP servers (unrestricted + restricted scopes)
  • Other bot tokens (like bot-008, agent-finance-bot) may have limited or no access to MCP servers depending on their Keycloak configuration. Use ingress.json for testing.

3. Base URL

The v0.1 API is accessible at:

  • API Endpoint: http://localhost/v0.1 or https://localhost/v0.1

Authentication: All endpoints require JWT Bearer token authentication via the Authorization header.

Test Commands

Test 1: List All Servers (Basic)

Description: Get the first page of servers with default pagination (100 items)

curl -X GET "http://localhost/v0.1/servers" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" | jq

Expected Response:

{
  "servers": [
    {
      "server": {
        "name": "io.mcpgateway/fininfo",
        "description": "...",
        "version": "1.0.0",
        "title": "Financial Info Server",
        "packages": [...],
        "_meta": {...}
      },
      "_meta": {...}
    },
    ...
  ],
  "metadata": {
    "nextCursor": "io.mcpgateway/some-server",
    "count": 100
  }
}

Test 2: List Servers with Limit

Description: Get first 5 servers only

curl -X GET "http://localhost/v0.1/servers?limit=5" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" | jq

Expected Response: ServerList with 5 items and pagination metadata

Test 3: List Servers with Pagination

Description: Get the next page using cursor from previous response

# First, get the first page and extract the cursor
CURSOR=$(curl -s -X GET "http://localhost/v0.1/servers?limit=5" \
  -H "Authorization: Bearer $TOKEN" | jq -r '.metadata.nextCursor')

# Then fetch the next page
curl -X GET "http://localhost/v0.1/servers?cursor=$CURSOR&limit=5" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" | jq

Expected Response: ServerList starting after the cursor position

Test 4: List Servers with Maximum Limit

Description: Test the maximum limit (1000 items)

curl -X GET "http://localhost/v0.1/servers?limit=1000" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" | jq

Expected Response: ServerList with up to 1000 items

Test 5: List Server Versions

Description: Get all versions for the Financial Info server

# Note: Server name must be URL-encoded
curl -X GET "http://localhost/v0.1/servers/io.mcpgateway%2Ffininfo/versions" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" | jq

Expected Response:

{
  "servers": [
    {
      "server": {
        "name": "io.mcpgateway/fininfo",
        "description": "...",
        "version": "1.0.0",
        ...
      },
      "_meta": {...}
    }
  ],
  "metadata": {
    "nextCursor": null,
    "count": 1
  }
}

Test 6: List Versions for Different Server

Description: Try with a different server (e.g., currenttime)

curl -X GET "http://localhost/v0.1/servers/io.mcpgateway%2Fcurrenttime/versions" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" | jq

Test 7: Get Specific Version (latest)

Description: Get detailed information for the latest version of Financial Info server

curl -X GET "http://localhost/v0.1/servers/io.mcpgateway%2Ffininfo/versions/latest" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" | jq

Expected Response:

{
  "server": {
    "name": "io.mcpgateway/fininfo",
    "description": "...",
    "version": "1.0.0",
    "title": "Financial Info Server",
    "repository": null,
    "websiteUrl": null,
    "packages": [
      {
        "registryType": "mcpb",
        "identifier": "io.mcpgateway/fininfo",
        "version": "1.0.0",
        "transport": {
          "type": "streamable-http",
          "url": "http://fininfo:8001"
        },
        "runtimeHint": "docker"
      }
    ],
    "_meta": {
      "io.mcpgateway/internal": {
        "path": "/fininfo",
        "is_enabled": true,
        "health_status": "healthy",
        "num_tools": 5,
        "tags": ["fininfo", "jira", "confluence"],
        "license": "MIT"
      }
    }
  },
  "_meta": {
    "io.mcpgateway/registry": {
      "last_checked": "2025-10-12T18:00:00Z",
      "health_status": "healthy"
    }
  }
}

Test 8: Get Specific Version (1.0.0)

Description: Get detailed information using explicit version number

curl -X GET "http://localhost/v0.1/servers/io.mcpgateway%2Ffininfo/versions/1.0.0" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" | jq

Expected Response: Same as Test 7 (we only support version 1.0.0 currently)

Test 9: Invalid Version

Description: Try to access a non-existent version

curl -X GET "http://localhost/v0.1/servers/io.mcpgateway%2Ffininfo/versions/2.0.0" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" | jq

Expected Response:

{
  "detail": "Version 2.0.0 not found"
}

Expected Status Code: 404

Test 10: Non-existent Server

Description: Try to access a server that doesn't exist

curl -X GET "http://localhost/v0.1/servers/io.mcpgateway%2Fnon-existent/versions" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" | jq

Expected Response:

{
  "detail": "Server not found"
}

Expected Status Code: 404

Test 11: Invalid Server Name Format

Description: Try to access a server with wrong namespace

curl -X GET "http://localhost/v0.1/servers/com.example%2Fserver/versions" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" | jq

Expected Response:

{
  "detail": "Server not found"
}

Expected Status Code: 404

Test 12: Unauthorized Access

Description: Try to access API without authentication

curl -X GET "http://localhost/v0.1/servers" \
  -H "Content-Type: application/json" | jq

Expected Response:

{
  "detail": "Not authenticated"
}

Expected Status Code: 401

Test 13: Invalid Token

Description: Try to access API with invalid token

curl -X GET "http://localhost/v0.1/servers" \
  -H "Authorization: Bearer invalid_token_here" \
  -H "Content-Type: application/json" | jq

Expected Response:

{
  "detail": "Could not validate credentials"
}

Expected Status Code: 401

Test 14: Permission-based Filtering (Non-admin User)

Description: Test that non-admin users only see servers they have access to

First, create a test user with limited permissions via the auth service, then:

# Get token for non-admin user
export USER_TOKEN=$(curl -s -X POST http://localhost:8888/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "username=testuser&password=testpass" | jq -r '.access_token')

# List servers as non-admin user
curl -X GET "http://localhost/v0.1/servers" \
  -H "Authorization: Bearer $USER_TOKEN" \
  -H "Content-Type: application/json" | jq

Expected Response: Only servers the user has access to (based on scopes.yml configuration)

Test 15: Via Nginx Proxy (Production Path)

Description: Test the API through Nginx reverse proxy

curl -X GET "http://localhost/v0.1/servers?limit=5" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" | jq

Expected Response: Same as Test 2, but routed through Nginx

Test 16: Verbose Output with Headers

Description: See full HTTP response including headers

curl -v -X GET "http://localhost/v0.1/servers?limit=5" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" 2>&1 | grep -E "(< HTTP|< Content-Type|< X-)"

Expected Headers:

  • HTTP/1.1 200 OK
  • Content-Type: application/json

Test 17: Test All Registered Servers

Description: Iterate through all servers and test version endpoint for each

# Get list of all servers
SERVERS=$(curl -s -X GET "http://localhost/v0.1/servers?limit=100" \
  -H "Authorization: Bearer $TOKEN" | jq -r '.servers[].server.name')

# Test each server
for server in $SERVERS; do
  echo "Testing server: $server"
  encoded_name=$(echo "$server" | sed 's/\//%2F/g')
  curl -s -X GET "http://localhost/v0.1/servers/$encoded_name/versions/latest" \
    -H "Authorization: Bearer $TOKEN" | jq -c '{name: .server.name, version: .server.version, status: "ok"}'
done

Test 18: Performance Test - Large Pagination

Description: Test pagination performance with large result sets

# Time the request
time curl -s -X GET "http://localhost/v0.1/servers?limit=500" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" | jq '.metadata.count'

Expected: Response should complete in < 2 seconds

Test 19: Concurrent Requests

Description: Test API under concurrent load

# Run 10 concurrent requests
for i in {1..10}; do
  curl -s -X GET "http://localhost/v0.1/servers?limit=10" \
    -H "Authorization: Bearer $TOKEN" &
done
wait
echo "All concurrent requests completed"

Test 20: Pretty Print Server Details

Description: Get nicely formatted output for a specific server

curl -s -X GET "http://localhost/v0.1/servers/io.mcpgateway%2Ffininfo/versions/latest" \
  -H "Authorization: Bearer $TOKEN" | jq '{
    name: .server.name,
    title: .server.title,
    description: .server.description,
    version: .server.version,
    transport_url: .server.packages[0].transport.url,
    num_tools: .server._meta."io.mcpgateway/internal".num_tools,
    health: ._meta."io.mcpgateway/registry".health_status
  }'

Test 21: Permission-Based Filtering (Restricted vs Full Access)

Description: Verify that users with restricted permissions only see authorized servers

Setup: Create restricted bot account if it doesn't exist

# Check if test-restricted-bot already exists
if [ ! -f .oauth-tokens/test-restricted-bot.json ]; then
  echo "Creating test-restricted-bot..."

  # Load Keycloak admin password from .env
  export $(grep KEYCLOAK_ADMIN_PASSWORD .env | xargs)

  # Create restricted bot (only has access to restricted servers)
  ./cli/user_mgmt.sh create-m2m \
    --name test-restricted-bot \
    --groups 'mcp-servers-restricted'
else
  echo "test-restricted-bot already exists, skipping creation"
fi

Test Commands:

# Step 1: Refresh the restricted bot's token
./scripts/refresh_m2m_token.sh test-restricted-bot

# Step 2: Load the restricted bot's token
export TOKEN_RESTRICTED=$(jq -r '.access_token' .oauth-tokens/test-restricted-bot-token.json)

# Step 3: Test v0.1 API with restricted token - should see only ~3 servers
echo "=== Testing with RESTRICTED token ==="
curl -s "http://localhost/v0.1/servers" \
  -H "Authorization: Bearer $TOKEN_RESTRICTED" | jq '{
    total_servers: (.servers | length),
    server_names: [.servers[].server.name]
  }'

# Step 4: Load the full access token for comparison
export TOKEN_FULL=$(jq -r '.access_token' .oauth-tokens/ingress.json)

# Step 5: Test v0.1 API with full access token - should see all servers
echo ""
echo "=== Testing with FULL ACCESS token ==="
curl -s "http://localhost/v0.1/servers" \
  -H "Authorization: Bearer $TOKEN_FULL" | jq '{
    total_servers: (.servers | length),
    server_names: [.servers[].server.name]
  }'

# Step 6: Compare the difference
echo ""
echo "=== COMPARISON ==="
echo "Restricted bot sees: $(curl -s "http://localhost/v0.1/servers" -H "Authorization: Bearer $TOKEN_RESTRICTED" | jq '.servers | length') servers"
echo "Full access sees: $(curl -s "http://localhost/v0.1/servers" -H "Authorization: Bearer $TOKEN_FULL" | jq '.servers | length') servers"

Expected Results:

  • Restricted bot (mcp-servers-restricted group): ~3 servers (currenttime, auth_server, mcpgw)
  • Full access (ingress.json token): ~7+ servers (all servers including fininfo, fininfo, sre-gateway)

This demonstrates that the v0.1 API correctly enforces permission-based filtering based on Keycloak groups and MCP scopes!


Verification Checklist

After running the tests, verify:

  • All successful requests return 200 status code
  • Pagination works correctly (cursor-based)
  • Server name format follows io.mcpgateway/{path} convention
  • All responses conform to Anthropic schema
  • Authentication is required for all endpoints
  • Non-admin users only see authorized servers (Test 21)
  • Restricted users see only restricted servers (Test 21)
  • Error responses include proper status codes (404, 401)
  • Version "latest" and "1.0.0" both work
  • Transport configuration includes correct proxy URLs
  • Metadata includes health status and internal info
  • URL encoding works for server names with special characters

Schema Validation

To validate responses against the Anthropic OpenAPI specification:

# Download the official OpenAPI spec
curl -o /tmp/anthropic-openapi.yaml \
  https://raw.githubusercontent.com/modelcontextprotocol/registry/refs/heads/main/docs/reference/api/openapi.yaml

# Use a tool like openapi-spec-validator or similar
# (Requires installation: pip install openapi-spec-validator)

Common Issues

Issue 1: Token Expired

Symptom: 401 Unauthorized or "Token has expired" error

Solution: Generate fresh credentials and reload token

# Step 1: Generate new token
./generate_creds.sh

# Step 2: Reload the token
export TOKEN=$(jq -r '.access_token' .oauth-tokens/ingress.json)

# Step 3: Verify it works
curl -s -X GET "http://localhost/v0.1/servers?limit=1" \
  -H "Authorization: Bearer $TOKEN" | jq '.servers[0].server.name'

Issue 2: URL Encoding

Symptom: 404 errors when server name contains /

Solution: Always URL-encode the server name

# Wrong: io.mcpgateway/server-name
# Correct: io.mcpgateway%2Fserver-name

Issue 3: Empty Response

Symptom: {"servers": [], "metadata": {"count": 0}}

Solution: Check if servers are registered and enabled

# List server files
ls ~/mcp-gateway/servers/*.json

# Check registry logs
docker compose logs registry | grep -i "loading servers"

Integration with Anthropic Tools

These endpoints are compatible with Anthropic MCP client tools. Example:

import httpx

# Configure client
client = httpx.Client(
    base_url="http://localhost:7860",
    headers={"Authorization": f"Bearer {token}"}
)

# List servers
response = client.get("/v0.1/servers", params={"limit": 10})
servers = response.json()

# Get server details
server_name = servers["servers"][0]["server"]["name"]
encoded_name = server_name.replace("/", "%2F")
details = client.get(f"/v0.1/servers/{encoded_name}/versions/latest")

Next Steps

After testing:

  1. Document any issues found
  2. Test with real MCP clients (Claude Desktop, etc.)
  3. Verify compatibility with Anthropic's official registry clients
  4. Performance testing with larger datasets
  5. Security testing (SQL injection, XSS, etc.)

References