Anthropic Registry API Test Commands¶
Note: The Anthropic API version is defined in
registry/constants.pyasANTHROPIC_API_VERSIONfor easy version management.
Overview¶
This document provides comprehensive curl commands to test all three endpoints of the Anthropic Registry API v0.1 implementation:
GET /v0.1/servers- List all MCP servers with paginationGET /v0.1/servers/{serverName}/versions- List versions for a specific serverGET /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.shscript 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. Useingress.jsonfor testing.
3. Base URL¶
The v0.1 API is accessible at:
- API Endpoint:
http://localhost/v0.1orhttps://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:
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:
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:
Expected Status Code: 404
Test 12: Unauthorized Access¶
Description: Try to access API without authentication
Expected Response:
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:
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 OKContent-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-restrictedgroup): ~3 servers (currenttime, auth_server, mcpgw) - Full access (
ingress.jsontoken): ~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
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:
- Document any issues found
- Test with real MCP clients (Claude Desktop, etc.)
- Verify compatibility with Anthropic's official registry clients
- Performance testing with larger datasets
- Security testing (SQL injection, XSS, etc.)
References¶
- Issue #175: Support Anthropic MCP Registry REST API v0.1
- OpenAPI Spec: https://raw.githubusercontent.com/modelcontextprotocol/registry/refs/heads/main/docs/reference/api/openapi.yaml
- API Guide: https://github.com/modelcontextprotocol/registry/blob/main/docs/guides/consuming/use-rest-api.md