McpExperiments
MCP Experiments
Documentation
MCP Experiments
These MCP experiments are a playground for better understanding the technology.
aspire runThis system makes the following endpoints available via its gateway:
- /my-mcp-server/mcp Experimental MCP Server
- /my-mcp-web-client Experimental MCP Host
- /identity Identity Server
Deploy as Azure Container Apps
$env:ASPIRE_CONTAINER_RUNTIME='podman'; aspire deployASPIRE_CONTAINER_RUNTIME=podman aspire deployClients & Compatibility
I have tested MCP authentication with the following clients.
csharp-sdk
var httpClientTransport = new HttpClientTransport(new()
{
Name = "Vibe MCP Server",
Endpoint = new Uri("https://gateway.gentlemeadow-305c776b.germanywestcentral.azurecontainerapps.io/my-mcp-server/mcp"),
TransportMode = HttpTransportMode.StreamableHttp,
OAuth = new()
{
ClientId = "mcp_console",
RedirectUri = new Uri("http://localhost:1179/callback"),
AuthorizationRedirectDelegate = AuthorizationUrl.Handle,
TokenCache = tokenCache,
},
}, http);
await using var mcpClient = await McpClient.CreateAsync(httpClientTransport);Works great.
MCP Inspector
npx @modelcontextprotocol/inspector⚠️ MCP inspector currently does not follow the `resource_metadata` URI of the `WWW-Authenticate` response header to locate the protected resource metadata according to Section 5 of RFC9728 (OAuth flow does not support resourceMetadataUrl #576). Instead it follows a set of hardcoded rules or permutations to find one:
1.
2.
3.
4.
When the returned WWW-Authenticate contains `Bearer realm="McpAuth", resource_metadata="http://localhost:5253/my-mcp-server/.well-known/oauth-protected-resource"`, MCP inspector should immediately acquire the protected resource metadata from . If no `resource_metadata` is provided, then it may fall back to trying permutations.
We can add a proxy endpoint at root level, that proxies the request to the subresource:
yarp.AddRoute("/.well-known/oauth-protected-resource/my-mcp-server/mcp", myMcpServer);Now MCP inspector successfully connects to the gatewayed MCP server at /my-mcp-sever.
MCPJam Inspector
npx @mcpjam/inspector@latestIf you run it against self-signed certs locally:
$env:NODE_TLS_REJECT_UNAUTHORIZED=0; npx @mcpjam/inspector@latest -vNODE_TLS_REJECT_UNAUTHORIZED=0 npx @mcpjam/inspector@latest -vAuthentication is a little bit flakey, but the OAuth Debugger works great.
Claude
Get the desktop app form Claude.
Web (Claude.ai)
Similar to the MCP Inspector, Claude.ai does not seem to support PRM behind a path like `/my-mcp-server/.well-known/oauth-protected-resource/mcp`. That means we need to make PRM available on root level like `/.well-known/oauth-protected-resource/my-mcp-server/mcp` and proxy it to `/my-mcp-server/.well-known/oauth-protected-resource/mcp`. Now Claude.ai authentication works.
Desktop
To install local MCP servers (stdio), we can easily add them to the `claude_desktop_config.json` like this:
{
"mcpServers": {
"getTime": {
"command": "D:\\McpExperiments\\MyMCPServer.Stdio\\bin\\Debug\\net9.0\\MyMCPServer.Stdio.exe"
},
"getCli": {
"command": "D:\\McpExperiments\\MyMCPServer.Stdio.Cli\\bin\\Debug\\net9.0\\MyMCPServer.Stdio.Cli.exe",
"args": [
"mcp"
]
}
}
}Custom connectors as remote MCP servers can also be added, with a OAuth ClientId & Secret. However custom connectors try to do auth at /authorize, not at at the authorize endpoint configured in the metadata of the authorization server configured in the protected resource metadata of the MCP server.
We can use mcp-remote for that. By default it uses _Dynamic Client Registration_ and stores its client credentials in `~\.mcp-auth`. But we can provide static oauth metadata:
$env:NODE_OPTIONS='--use-system-ca'
npx mcp-remote 'http://localhost:5253/my-mcp-server' 63113 --static-oauth-client-info '{\"client_id\":\"mcp-remote\"}'set NODE_OPTIONS=--use-system-ca
npx mcp-remote http://localhost:5253/my-mcp-server 63113 --static-oauth-client-info "{\"client_id\":\"mcp-remote\"}"If `set NODE_OPTIONS=--use-system-ca` does not work anymore (`--use-system-ca is not allowed in NODE_OPTIONS`), consider `$env:NODE_TLS_REJECT_UNAUTHORIZED = "0"`.
Powershell does have an escaping problem, so we best put the oauth data in a separate json file and reference it like this:
npx mcp-remote 'http://localhost:5253/my-mcp-server' 63113 --static-oauth-client-info "@D:\McpExperiments\MyMCPServer.Sse\mcp-remote-oauth-client-info.json"In the `claude_desktop_config.json` it looks like this:
{
"mcpServers": {
"getVibe": {
"command": "npx",
"args": [
"mcp-remote",
"http://localhost:5253/my-mcp-server",
"63113",
"--static-oauth-client-info",
"@D:\\McpExperiments\\MyMCPServer.Sse\\mcp-remote-oauth-client-info.json"
],
"env": {
"NODE_OPTIONS": "--use-system-ca"
}
}
},
"isUsingBuiltInNodeForMcp": false
}Or via script claude_desktop.cmd:
{
"mcpServers": {
"getVibe": {
"command": "D:\\McpExperiments\\MyMCPServer.Sse\\claude_desktop.cmd"
}
}
}However, this currently fails during "Completing authorization" with a 404. What endpoint is it trying to call?
The protected resource metadata is detected with a `testTransport`, but not fed forward into the actual transport in connectToRemoteServer():
const transport = sseTransport ? new SSEClientTransport(url, {
authProvider,
requestInit: { headers },
eventSourceInit
}) : new StreamableHTTPClientTransport(url, {
authProvider,
requestInit: { headers }
});
try {
debugLog("Attempting to connect to remote server", { sseTransport });
if (client) {
debugLog("Connecting client to transport");
await client.connect(transport);
} else {
debugLog("Starting transport directly");
await transport.start();
if (!sseTransport) {
debugLog("Creating test transport for HTTP-only connection test");
const testTransport = new StreamableHTTPClientTransport(url, { authProvider, requestInit: { headers } });
const testClient = new Client({ name: "mcp-remote-fallback-test", version: "0.0.0" }, { capabilities: {} });
await testClient.connect(testTransport);
}
}
return transport;
} catch (error) {
transport._resourceMetadataUrl = testTransport._resourceMetadataUrl;//this line would fix it (todo: pr!)
//...interactive authentication
}I have proposed the fix with Resource metadata is remembered throughout the entire login flow. #167. Until this is merged, we can to compile `mcp-remote` locally and set it up like this:
git clone https://github.com/halllo/mcp-remote.git
cd mcp-remote
git checkout -b remembers_resource_metadata origin/remembers_resource_metadata
pnpm install
pnpm build
npm link #make it available everywhere
npm list -g --depth=0 #to verify its actually available
npx mcp-remote #use linked version everywhereOr without `npm link`:
npx --package=/Users/Manuel.Naujoks/Projects/mcp-remote mcp-remote https://…Make sure your Claude Desktop instance does not use its built-in Node.js, but instead uses your operating system's version of Node.js. Under Settings / Extensions / Advanced Settings you should see the same Node.js version that you used when you ran `npm link`.
ChatGPT
MCP support requires ChatGPT Plus. Then users can enable "Developer mode" (which is still in BETA) and create a new connector. Custom OAuth `client_id` is not supported.
Adding a localhost hosted MCP server only resulted in "Error fetching OAuth configuration".
Nanobot
To better test the MCP servers of this project, we can use a local MCP host like nanobot. It seems to support OAuth and mcp-ui.
export OPENAI_API_KEY=sk-proj-...
nanobot run ./nanobot.yamlIt seems to require client_secret and auth_endpoint, even though the client config does not require a secret and the authorize endpoint can be determined based on PRM and authorization server metadata.
However nanobot still fails with a weird error:
failed to setup auth: failed to create oauth proxy: invalid mode: middlewareResources
Frequently asked questions
What is McpExperiments?
McpExperiments is MCP Experiments
How do I install McpExperiments?
Open the GitHub repository and follow its README. Most MCP servers are added to your client's MCP config, then called by your agent.
Is McpExperiments open source?
Yes — it is hosted on GitHub at https://github.com/halllo/McpExperiments and has 1 stars.
Related MCP tools
Unity MCP acts as a bridge between AI assistants and your Unity Editor. Give your LLM tools to manage assets, control scenes, edit scripts, and automate tasks within Unity.
AI Skills, MCP Tools, and CLI for Unity Engine. Full AI develop and test loop. Use cli for quick setup. Efficient token usage, advanced tools. Any C# method may be turned into a tool by a single line. Works with Claude Code, Gemini, Copilot, Cursor and any other absolutely for free.
Catalog of official Microsoft MCP (Model Context Protocol) server implementations for AI-powered data access and tool integration
An MCP server that allows MCP clients like Claude Desktop or Cursor to perform actions in the Unity Editor C#-based implementation.
The official C# SDK for Model Context Protocol servers and clients. Maintained in collaboration with Microsoft. Trusted by 3500+ developers.
Model Context Protocol (MCP) plugin to connect with Unity Editor — designed for OpenAI, Gemini, Claude, Deepseek and Grok interoperability
Run your own MCP server? See who uses it and what to fix.
Measure it with TrackMCP