Remote Credentials
Remote Credentials Management
When running the Play Store MCP server with streamable-http transport, you can dynamically update credentials without restarting the server. This is useful for:
- Multi-tenant deployments where different clients use different service accounts
- Rotating credentials without downtime
- Testing with different accounts
- Remote server deployments where file access is restricted
Starting the Server
Start the server with HTTP transport:
Or with environment variables:
Updating Credentials
The server exposes a /credentials endpoint that accepts POST requests with credentials in various formats.
Access control: By default the
/credentialsendpoint only accepts requests from localhost (loopback addresses). Behind a reverse proxy this loopback check is not sufficient — proxied requests arrive from the proxy (a loopback address), so the check would pass for every remote client. When exposing the endpoint through a proxy, set thePLAY_STORE_MCP_ADMIN_TOKENenvironment variable: with it set, the endpoint requires anAuthorization: Bearer <token>header (compared in constant time) and accepts authenticated requests from any host.
Method 1: Send Credentials JSON Object
Send the service account credentials directly as a JSON object:
curl -X POST http://localhost:8000/credentials \
-H "Content-Type: application/json" \
-d '{
"credentials": {
"type": "service_account",
"project_id": "your-project-id",
"private_key_id": "your-key-id",
"private_key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n",
"client_email": "your-service-account@your-project.iam.gserviceaccount.com",
"client_id": "123456789",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs/your-service-account"
}
}'
Method 2: Send Credentials JSON String
Send the credentials as a JSON string:
CREDS=$(cat /path/to/service-account.json | jq -c .)
curl -X POST http://localhost:8000/credentials \
-H "Content-Type: application/json" \
-d "{\"credentials\": \"$CREDS\"}"
Method 3: Send Base64-Encoded Credentials
Send the credentials as a base64-encoded string (useful for environment variables):
CREDS_B64=$(cat /path/to/service-account.json | base64 -w 0)
curl -X POST http://localhost:8000/credentials \
-H "Content-Type: application/json" \
-d "{\"credentials_base64\": \"$CREDS_B64\"}"
Response Codes
200 OK: Credentials updated successfully400 Bad Request: Invalid request format or malformed JSON401 Unauthorized: Credentials are invalid or cannot be authenticated500 Internal Server Error: Server error during credential update
Success Response
Error Response
Python Example
import json
import requests
# Load credentials from file
with open('/path/to/service-account.json') as f:
credentials = json.load(f)
# Update server credentials
response = requests.post(
'http://localhost:8000/credentials',
json={'credentials': credentials}
)
if response.status_code == 200:
print("Credentials updated successfully")
else:
print(f"Error: {response.json()['error']}")
Security Considerations
- Use HTTPS in production: Always use HTTPS when sending credentials over the network
- Authenticate the endpoint: Behind a reverse proxy the built-in localhost check is
bypassed (the peer is the proxy), so set
PLAY_STORE_MCP_ADMIN_TOKENand require anAuthorization: Bearerheader. Proxy-level auth (e.g.auth_basic) is a useful extra layer but must not be the only gate. - Network isolation: Run the server in a private network or use VPN
- Credential rotation: Regularly rotate service account keys and the admin token
- Audit logging: Monitor credential update requests
- Use a strong token and rate-limit: Generate a high-entropy token (e.g.
openssl rand -hex 32) and throttle repeated invalidAuthorizationattempts at the reverse proxy (e.g. nginxlimit_req), since the endpoint itself does not rate-limit.
Example with Authentication
Set an admin token on the server:
export PLAY_STORE_MCP_ADMIN_TOKEN="$(openssl rand -hex 32)"
play-store-mcp --transport streamable-http --host 127.0.0.1 --port 8000
Then send it with each request:
curl -X POST https://your-server.com/credentials \
-H "Authorization: Bearer $PLAY_STORE_MCP_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d @credentials.json
Behind nginx, forward the Authorization header to the app (optionally layering
auth_basic on top for defence in depth):
location /credentials {
proxy_set_header Authorization $http_authorization;
proxy_pass http://localhost:8000;
}
Troubleshooting
Error: "Missing 'credentials' or 'credentials_base64' in request body"
- Ensure your request includes either credentials or credentials_base64 field
Error: "Invalid JSON in credentials string"
- Verify the credentials JSON is properly formatted
- Use jq to validate: cat credentials.json | jq .
Error: "Invalid credentials" - Verify the service account has the necessary permissions - Check that the credentials file is not corrupted - Ensure the service account is enabled in Google Cloud Console
Error: "credentials must be a string or object"
- The credentials field must be either a JSON object or a JSON string
- Don't send other types like numbers or arrays