Skip to content

Instantly share code, notes, and snippets.

@ochafik

ochafik/SKILL.md Secret

Last active November 6, 2025 16:09
Show Gist options
  • Select an option

  • Save ochafik/eccd6a043ac64beb49cecab645d3a85d to your computer and use it in GitHub Desktop.

Select an option

Save ochafik/eccd6a043ac64beb49cecab645d3a85d to your computer and use it in GitHub Desktop.
MCP Calling Skill
#!/bin/bash
set -euo pipefail
#
# Usage:
# ./mcp-auth.sh <mcp-server-url> [client-id]
#
# Examples:
# ./mcp-auth.sh http://localhost:3001/mcp | tee creds.json
# ./mcp-auth.sh https://example-server.modelcontextprotocol.io/mcp | tee creds.json
#
# Implements MCP OAuth 2.1 flow per specification (2025-06-18):
# - RFC 8414: OAuth Authorization Server Metadata
# - RFC 8707: Resource Indicators
# - PKCE required for all clients
#
MCP_SERVER="$1"
CLIENT_ID="${2:-}" # Will be set via registration if empty
# Extract base URL (protocol + host + optional port)
if [[ $MCP_SERVER =~ ^(https?://[^/]+) ]]; then
BASE_URL="${BASH_REMATCH[1]}"
else
echo "Error: Invalid MCP server URL: $MCP_SERVER" >&2
exit 1
fi
echo "==> Step 1: Fetching OAuth Protected Resource metadata" >&2
RESOURCE_METADATA_URL="${BASE_URL}/.well-known/oauth-protected-resource"
echo " From: $RESOURCE_METADATA_URL" >&2
if ! RESOURCE_METADATA="$(curl --silent --fail "$RESOURCE_METADATA_URL")"; then
echo "Error: Failed to fetch OAuth Protected Resource metadata" >&2
# echo "The server may not support OAuth, or the well-known endpoint is not available." >&2
# exit 1
RESOURCE_URI="${MCP_SERVER}"
AUTH_SERVER_URL="${BASE_URL}/"
else
# Extract resource URI (RFC 8707 requirement)
RESOURCE_URI="$(echo "$RESOURCE_METADATA" | jq -r '.resource')"
if [[ "$RESOURCE_URI" == "null" ]]; then
echo "Error: No resource URI found in protected resource metadata" >&2
exit 1
fi
# Extract authorization server URL
AUTH_SERVER_URL="$(echo "$RESOURCE_METADATA" | jq -r '.authorization_servers[0]')"
if [[ "$AUTH_SERVER_URL" == "null" ]]; then
echo "Error: No authorization server found in protected resource metadata" >&2
exit 1
fi
fi
echo " Resource URI: $RESOURCE_URI" >&2
echo " Authorization server URL: $AUTH_SERVER_URL" >&2
echo "" >&2
echo "==> Step 2: Fetching OAuth Authorization Server metadata" >&2
AUTH_SERVER_METADATA_URL="${AUTH_SERVER_URL}.well-known/oauth-authorization-server"
echo " From: $AUTH_SERVER_METADATA_URL" >&2
if ! AUTH_SERVER_METADATA="$(curl --silent --fail "$AUTH_SERVER_METADATA_URL")"; then
echo "Error: Failed to fetch OAuth Authorization Server metadata" >&2
exit 1
fi
# Extract authorization endpoint (RFC 8414)
AUTH_ENDPOINT="$(echo "$AUTH_SERVER_METADATA" | jq -r '.authorization_endpoint')"
if [[ "$AUTH_ENDPOINT" == "null" ]]; then
echo "Error: No authorization endpoint found in authorization server metadata" >&2
exit 1
fi
echo " Authorization endpoint: $AUTH_ENDPOINT" >&2
# Extract token endpoint
TOKEN_ENDPOINT="$(echo "$AUTH_SERVER_METADATA" | jq -r '.token_endpoint')"
if [[ "$TOKEN_ENDPOINT" == "null" ]]; then
echo "Error: No token endpoint found in authorization server metadata" >&2
exit 1
fi
echo " Token endpoint: $TOKEN_ENDPOINT" >&2
# Scopes are optional in authorization server metadata
SCOPES="$(echo "$AUTH_SERVER_METADATA" | jq -r 'if .scopes_supported then .scopes_supported | join(" ") else "" end')"
if [[ -n "$SCOPES" ]]; then
echo " Scopes supported: $SCOPES" >&2
fi
echo "" >&2
echo "==> Step 3: Dynamic Client Registration (RFC 7591)" >&2
# Check if registration endpoint is available
REGISTRATION_ENDPOINT="$(echo "$AUTH_SERVER_METADATA" | jq -r '.registration_endpoint')"
if [[ "$REGISTRATION_ENDPOINT" != "null" && -z "$CLIENT_ID" ]]; then
echo " Registration endpoint: $REGISTRATION_ENDPOINT" >&2
echo " Registering client dynamically..." >&2
# Register a new OAuth client
REGISTRATION_REQUEST='{
"client_name": "mcp-cli",
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"redirect_uris": ["http://localhost:9876/callback"],
"token_endpoint_auth_method": "none"
}'
if REGISTRATION_RESPONSE="$(curl --silent --fail -X POST "$REGISTRATION_ENDPOINT" \
-H "Content-Type: application/json" \
-d "$REGISTRATION_REQUEST")"; then
CLIENT_ID="$(echo "$REGISTRATION_RESPONSE" | jq -r '.client_id')"
if [[ "$CLIENT_ID" == "null" || -z "$CLIENT_ID" ]]; then
echo "Error: Failed to extract client_id from registration response" >&2
echo "Response: $REGISTRATION_RESPONSE" >&2
exit 1
fi
echo " ✓ Client registered with ID: $CLIENT_ID" >&2
else
echo "Error: Failed to register client dynamically" >&2
echo "You may need to provide a pre-registered client ID as the second argument" >&2
exit 1
fi
else
if [[ "$REGISTRATION_ENDPOINT" == "null" ]]; then
echo " No registration endpoint available" >&2
if [[ -z "$CLIENT_ID" ]]; then
echo "Error: No client ID provided and dynamic registration not available" >&2
echo "Usage: $0 <mcp-server-url> <client-id>" >&2
exit 1
fi
fi
echo " Client ID: $CLIENT_ID" >&2
fi
# Ensure we have a client ID at this point
if [[ -z "$CLIENT_ID" ]]; then
echo "Error: No client ID available" >&2
exit 1
fi
echo "" >&2
echo "==> Step 4: Starting OAuth authorization flow" >&2
echo " Client ID: $CLIENT_ID" >&2
echo " Resource: $RESOURCE_URI (RFC 8707)" >&2
echo "" >&2
# Build oauth2c command
# NOTE: oauth2c v1.17.2 does not support the --resource flag required by RFC 8707
# MCP spec (2025-06-18) REQUIRES the resource parameter in authorization requests
# This is a known limitation - see https://github.com/cloudentity/oauth2c/issues
echo "WARNING: oauth2c does not support RFC 8707 resource parameter" >&2
echo " MCP spec compliance requires --resource '$RESOURCE_URI'" >&2
echo " Proceeding without resource parameter (may fail with spec-compliant servers)" >&2
echo "" >&2
OAUTH_ARGS=(
"$MCP_SERVER"
--authorization-endpoint "$AUTH_ENDPOINT"
--token-endpoint "$TOKEN_ENDPOINT"
--grant-type authorization_code
--response-types code
--response-mode query
--client-id "$CLIENT_ID"
--auth-method none
--pkce
)
# Add scopes if present
if [[ -n "$SCOPES" ]]; then
OAUTH_ARGS+=(--scopes "$SCOPES")
fi
# TODO: Need to add resource parameter manually to authorization URL
# The resource parameter should be: resource=$RESOURCE_URI
# This requires either:
# 1. Patching oauth2c to support --resource flag
# 2. Using a different OAuth client tool
# 3. Manually constructing the authorization URL with the resource parameter
oauth2c "${OAUTH_ARGS[@]}" | \
jq --arg mcp_server "$MCP_SERVER" '. + {mcp_server: $mcp_server}'
#!/bin/bash
set -euo pipefail
CREDS_FILE="${1}"
METHOD="${2}"
PARAMS="${3}"
MCP_SERVER="$(jq -r '.mcp_server' "$CREDS_FILE")"
TOKEN_TYPE="$(jq -r '.token_type' "$CREDS_FILE")"
ACCESS_TOKEN="$(jq -r '.access_token' "$CREDS_FILE")"
common_args=(
-H "Authorization: $TOKEN_TYPE $ACCESS_TOKEN" \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
)
INITIALIZE=$( \
curl -D - -X POST "$MCP_SERVER" "${common_args[@]}" \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "initialize",
"params": {
"capabilities": {},
"clientInfo": {
"name": "foo",
"version": "1"
},
"protocolVersion": "1"
}
}' 2>&1
)
MCP_SESSION_ID=$(echo "$INITIALIZE" | grep 'mcp-session-id' | sed -E 's/.*mcp-session-id: ([a-f0-9-]+).*/\1/')
args=(
-X POST "$MCP_SERVER"
"${common_args[@]}"
-H "mcp-session-id: $MCP_SESSION_ID"
--silent
# -v
-d "{\"jsonrpc\": \"2.0\", \"id\": \"2\", \"method\": \"$METHOD\", \"params\": $PARAMS}"
)
# echo "${args[@]}" >&2
OUTPUT=$(curl "${args[@]}")
# echo "$OUTPUT" >&2
echo "$OUTPUT" | \
grep '^data: ' | \
sed 's/^data: //' | \
jq '.result // .error'

To call an MCP server, one may need auth. Here's how:

./mcp-auth.sh https://example-server.modelcontextprotocol.io/mcp > creds.json

Then can call any MCP request:

./mcp-req.sh creds.json tools/list '{}'

./mcp-req.sh creds.json tools/call '{"name": "add", "arguments": {"a": 1, "b": 2}}'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment