Exact Match Site ID MCP Connector
This service exposes Exact Match Site ID data to MCP-compatible AI clients such as ChatGPT, Claude, Cursor, and other tools that can call MCP servers.
Stack
- TypeScript
- Hono for HTTP routes
- Official MCP SDK for MCP protocol handling
- Zod for input validation
- Laravel
dataas the source of truth
Local Setup
- Copy
.env.exampleto.env. - Set
LARAVEL_API_BASE_URLto the Laravel API base URL. - Set
LARAVEL_MCP_PROXY_TOKENto the same value configured in Laravel forservices.mcp_proxy.internal_token. - Set
OAUTH_TOKEN_SECRETto at least 32 random characters. - Install dependencies with
npm install. - Start local development with
npm run dev.
The default local service URL is http://localhost:8787.
Useful URLs
- Health:
GET /health - MCP endpoint:
POST /mcp - OAuth authorization metadata:
GET /.well-known/oauth-authorization-server - MCP metadata:
GET /.well-known/mcp-server - Widget:
GET /widgets/site-id
Development Auth
When MCP_DEV_AUTH_ENABLED=true, a local auth code can be created by calling:
GET /oauth/dev/start?clerk_user_id=user_xxx
Production should replace this dev handoff with the real Exact Match/Clerk login callback.
Local OAuth Test Flow
Use this flow to test OAuth locally before connecting the server to ChatGPT Apps.
- Make sure
.envcontains a local redirect allowlist:
OAUTH_ALLOWED_REDIRECT_URIS=http://localhost:8787/oauth/dev/callback
MCP_DEV_AUTH_ENABLED=true
- Start the MCP server:
npm run dev
- Open the dev authorization URL with a real Clerk user id:
http://localhost:8787/oauth/dev/start?clerk_user_id=user_xxx
The browser redirects to:
http://localhost:8787/oauth/dev/callback?code=...&state=...
-
Copy the
codevalue from the callback response. -
Exchange the code for an MCP access token:
$code = "paste-code-here"
Invoke-RestMethod `
-Method Post `
-Uri "http://localhost:8787/oauth/token" `
-ContentType "application/x-www-form-urlencoded" `
-Body @{
grant_type = "authorization_code"
client_id = "local-dev"
redirect_uri = "http://localhost:8787/oauth/dev/callback"
code = $code
}
Successful response:
{
"access_token": "...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "...",
"scope": "site_id:read"
}
Use access_token as:
Authorization: Bearer <access_token>
This token authenticates AI app requests into the MCP server. The MCP server still authenticates to Laravel separately with LARAVEL_MCP_PROXY_TOKEN.