Skip to Main
schemawp
Back to docs

Nginx returning 404 on /.well-known/

SchemaWP Pro exposes an MCP server that uses OAuth 2.0. MCP clients (such as Claude.ai, ChatGPT, and Claude Code) discover how to authenticate by fetching two path-scoped well-known URLs:

  • https://yoursite.com/.well-known/oauth-authorization-server/wp-json/scwp-acss-mcp/v1
  • https://yoursite.com/.well-known/oauth-protected-resource/wp-json/scwp-acss-mcp/v1/mcp

On most WordPress hosts, SchemaWP serves these URLs automatically. On some managed hosts — especially those running Nginx at the edge — the web server returns a 404 before WordPress ever runs, so the plugin cannot respond.

This guide explains how to diagnose the problem and apply a static-file workaround that several customers have used successfully on hosts like WP Engine. For general server, CDN, and WordPress fixes, see MCP Connection Fails: /.well-known/ URL Returns 404.

Symptoms

  • MCP clients fail to connect via OAuth and report discovery or authentication errors.
  • Visiting the path-scoped discovery URLs above in a browser returns 404 Not Found.
  • SchemaWP is active and other MCP endpoints (authorize, token, register) work fine under /wp-json/.

Diagnose the issue

Run these checks from a terminal (replace yoursite.com with your actual domain):

First, test the WordPress REST diagnostic mirrors:

# Should return JSON — if this 404s, SchemaWP may not be active.
curl -i https://yoursite.com/wp-json/scwp-acss-mcp/v1/.well-known/oauth-authorization-server
curl -i https://yoursite.com/wp-json/scwp-acss-mcp/v1/.well-known/oauth-protected-resource

Then test the path-scoped discovery URLs that MCP clients actually fetch:

curl -i https://yoursite.com/.well-known/oauth-authorization-server/wp-json/scwp-acss-mcp/v1
curl -i https://yoursite.com/.well-known/oauth-protected-resource/wp-json/scwp-acss-mcp/v1/mcp

How to read the results

  • REST mirrors return JSON, path-scoped URLs return 404 — host-level block. The web server intercepts /.well-known/* before WordPress loads. Continue with the static-file workaround below, or ask your host to pass these paths through to PHP.
  • Both return 404 — SchemaWP may not be active, or permalinks/REST API need attention. See the general troubleshooting guide.
  • Both return JSON — everything is working. No workaround needed.

Note: The /wp-json/scwp-acss-mcp/v1/.well-known/… routes are diagnostic mirrors only. MCP clients discover via the path-scoped /.well-known/oauth-*/wp-json/scwp-acss-mcp/… URLs advertised by SchemaWP.

Workaround: create static .well-known files

When the host blocks /.well-known/ at the server level, you can place the required JSON metadata files directly on disk. The web server will serve them as static files, bypassing the block that prevents WordPress from handling those requests.

What gets created

Two files inside nested directories at your WordPress root (same level as wp-config.php):

/your-wordpress-root/
└── .well-known/
    ├── oauth-authorization-server/
    │   └── wp-json/
    │       └── scwp-acss-mcp/
    │           └── v1
    └── oauth-protected-resource/
        └── wp-json/
            └── scwp-acss-mcp/
                └── v1/
                    └── mcp

v1 and mcp are files with no file extension. On WP Engine, your WordPress root is typically the public folder in SFTP (e.g. /sites/yoursitename/).

Option A: One-time PHP snippet (recommended)

This approach uses a temporary PHP snippet to generate both files with the correct URLs for your site. It mirrors exactly what SchemaWP would serve dynamically.

Works with Code Snippets, WPCodeBox, or any snippet plugin that can run PHP once.

Steps

  1. Install and activate a snippet plugin if you don’t already have one.
  2. Create a new PHP snippet and paste the code below.
  3. Activate the snippet.
  4. While logged in as an administrator, visit https://yoursite.com/?scwp_install_well_known=1 to trigger the installer.
  5. You should see a success message with links to test both files.
  6. Delete or deactivate the snippet immediately — it is a one-time installer, not something that should stay active.

Installer snippet

<?php
/**
 * SchemaWP — one-time .well-known OAuth discovery file installer.
 * Run once via ?scwp_install_well_known=1, then delete this snippet.
 */
add_action( 'init', function () {
	if ( ! isset( $_GET['scwp_install_well_known'] ) ) {
		return;
	}

	if ( ! current_user_can( 'manage_options' ) ) {
		wp_die( 'Unauthorized.' );
	}

	$issuer   = untrailingslashit( rest_url( 'scwp-acss-mcp/v1' ) );
	$resource = untrailingslashit( rest_url( 'scwp-acss-mcp/v1/mcp' ) );

	$auth_dir     = ABSPATH . '.well-known/oauth-authorization-server/wp-json/scwp-acss-mcp';
	$resource_dir = ABSPATH . '.well-known/oauth-protected-resource/wp-json/scwp-acss-mcp/v1';

	if ( ! wp_mkdir_p( $auth_dir ) || ! wp_mkdir_p( $resource_dir ) ) {
		wp_die( 'Could not create .well-known directories.' );
	}

	$auth_server = array(
		'issuer'                                => $issuer,
		'authorization_endpoint'                => untrailingslashit( rest_url( 'scwp-acss-mcp/v1/authorize' ) ),
		'token_endpoint'                        => untrailingslashit( rest_url( 'scwp-acss-mcp/v1/token' ) ),
		'registration_endpoint'                 => untrailingslashit( rest_url( 'scwp-acss-mcp/v1/register' ) ),
		'response_types_supported'              => array( 'code' ),
		'grant_types_supported'                 => array( 'authorization_code' ),
		'code_challenge_methods_supported'      => array( 'S256' ),
		'token_endpoint_auth_methods_supported' => array( 'none' ),
		'scopes_supported'                      => array( 'mcp' ),
		'resource_parameter_supported'          => true,
		'authorization_response_iss_parameter_supported' => true,
		'client_id_metadata_document_supported' => true,
	);

	$protected_resource = array(
		'resource'                 => $resource,
		'authorization_servers'    => array( $issuer ),
		'bearer_methods_supported' => array( 'header' ),
		'scopes_supported'         => array( 'mcp' ),
	);

	$written = array(
		file_put_contents( $auth_dir . '/v1', wp_json_encode( $auth_server, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ) ),
		file_put_contents( $resource_dir . '/mcp', wp_json_encode( $protected_resource, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ) ),
	);

	if ( in_array( false, $written, true ) ) {
		wp_die( 'Failed to write one or more discovery files. Check file permissions.' );
	}

	$auth_url = home_url( '/.well-known/oauth-authorization-server/wp-json/scwp-acss-mcp/v1' );
	$res_url  = home_url( '/.well-known/oauth-protected-resource/wp-json/scwp-acss-mcp/v1/mcp' );

	wp_die(
		'Success! Created path-scoped OAuth discovery files.<br><br>'
		. '<strong>Delete this snippet now.</strong><br><br>'
		. '<a href="' . esc_url( $auth_url ) . '">Test authorization server</a><br>'
		. '<a href="' . esc_url( $res_url ) . '">Test protected resource</a>'
	);
}, 1 );

Option B: Upload files manually (SFTP / file manager)

If you prefer not to use a snippet plugin, create the directory structure and files manually via SFTP or your host’s file manager.

1. Create the authorization-server file

Create .well-known/oauth-authorization-server/wp-json/scwp-acss-mcp/v1 (no file extension). Replace https://yoursite.com with your site URL:

{
  "issuer": "https://yoursite.com/wp-json/scwp-acss-mcp/v1",
  "authorization_endpoint": "https://yoursite.com/wp-json/scwp-acss-mcp/v1/authorize",
  "token_endpoint": "https://yoursite.com/wp-json/scwp-acss-mcp/v1/token",
  "registration_endpoint": "https://yoursite.com/wp-json/scwp-acss-mcp/v1/register",
  "response_types_supported": ["code"],
  "grant_types_supported": ["authorization_code"],
  "code_challenge_methods_supported": ["S256"],
  "token_endpoint_auth_methods_supported": ["none"],
  "scopes_supported": ["mcp"],
  "resource_parameter_supported": true,
  "authorization_response_iss_parameter_supported": true,
  "client_id_metadata_document_supported": true
}

2. Create the protected-resource file

Create .well-known/oauth-protected-resource/wp-json/scwp-acss-mcp/v1/mcp with this content:

{
  "resource": "https://yoursite.com/wp-json/scwp-acss-mcp/v1/mcp",
  "authorization_servers": ["https://yoursite.com/wp-json/scwp-acss-mcp/v1"],
  "bearer_methods_supported": ["header"],
  "scopes_supported": ["mcp"]
}

Verify the fix

After creating the files, confirm both path-scoped URLs return HTTP 200 with valid JSON:

curl -i https://yoursite.com/.well-known/oauth-authorization-server/wp-json/scwp-acss-mcp/v1
curl -i https://yoursite.com/.well-known/oauth-protected-resource/wp-json/scwp-acss-mcp/v1/mcp

A successful response looks like:

HTTP/2 200
content-type: application/json (or application/octet-stream — both are fine)

{"issuer":"https://yoursite.com/wp-json/scwp-acss-mcp/v1","authorization_endpoint":"https://yoursite.com/wp-json/scwp-acss-mcp/v1/authorize", ...}

Once both URLs return JSON, retry connecting your MCP client via OAuth.

Important notes

Static files vs. dynamic responses

The workaround creates static JSON files. SchemaWP normally generates these dynamically so URLs always match your home_url() and REST routes. If you change your site URL (e.g. staging → production, HTTP → HTTPS, domain migration), you must regenerate the files with the updated URLs.

Content-Type header

Some hosts serve these files with Content-Type: application/octet-stream instead of application/json. This is acceptable — MCP clients parse the response body as JSON regardless. The workaround has been confirmed working with this content type on WP Engine.

OAuth endpoints are unaffected

Only the two discovery URLs need static files. The actual OAuth flow (authorize, token, register) and the MCP endpoint continue to be handled by WordPress/SchemaWP under /wp-json/scwp-acss-mcp/v1/. Those routes are not blocked on affected hosts.

Host support ticket (optional)

If you prefer a server-level fix instead of static files, contact your host and ask them to allow /.well-known/oauth-authorization-server/wp-json/scwp-acss-mcp/v1 and /.well-known/oauth-protected-resource/wp-json/scwp-acss-mcp/v1/mcp to pass through to WordPress. Some managed hosts can adjust Nginx/Apache rules for these paths.

Security

The discovery files contain only public metadata — no secrets. They are safe to serve publicly and are required to be publicly accessible by the OAuth and MCP specifications.

Still having trouble?

If both path-scoped /.well-known/ URLs return JSON but OAuth connection still fails:

  1. Confirm SchemaWP is active and MCP is enabled on SchemaWP → Connections.
  2. Test the MCP endpoint: curl -i https://yoursite.com/wp-json/scwp-acss-mcp/v1/mcp
  3. Open SchemaWP → Connections and verify the discovery URLs shown there match your domain.
  4. Contact SchemaWP Support with the output of the four curl commands from the diagnose section above.

Related