MCP Experiments
About
An experimental dotnet MCP server that returns the current time, based on Laurent Kempé's tutorial.
Details
- Author
- halllo
- Categories
- Developer Tools
Jump to
Setup
Install MCP Experiments in your MCP client (Claude Desktop, Cursor, Windsurf, and others).
Repository: https://github.com/halllo/McpExperiments
Follow the installation instructions in the repository README, then restart your MCP client.
An experimental dotnet MCP server that returns the current time, based on Laurent Kempé's tutorial.
These MCP experiments are a playground for better understanding the technology.
This system makes the following endpoints available via its gateway:
- /my-mcp-server/mcpExperimental MCP Server
- /my-mcp-web-clientExperimental MCP Host
- /identityIdentity Server
$env:ASPIRE_CONTAINER_RUNTIME='podman'; aspire deploy
ASPIRE_CONTAINER_RUNTIME=podman aspire deploy
I have tested MCP authentication with the following clients.
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);
⚠️ MCP inspector currently does not follow theresource_metadataURI of theWWW-Authenticateresponse header to locate the protected resource metadata according toSection 5 of RFC9728(OAuth flow does not support resourceMetadataUrl #576). Instead it follows a set of hardcoded rules or permutations to find one:
- http://localhost:5253/.well-known/oauth-protected-resource/my-mcp-server
- http://localhost:5253/.well-known/oauth-protected-resource
- http://localhost:5253/.well-known/oauth-authorization-server
- http://localhost:5253/.well-known/openid-configuration
When the returned WWW-Authenticate containsBearer realm="McpAuth", resource_metadata="http://localhost:5253/my-mcp-server/.well-known/oauth-protected-resource", MCP inspector should immediately acquire the protected resource metadata fromhttp://localhost:5253/my-mcp-server/.well-known/oauth-protected-resource. If noresource_metadatais 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.
If you run it against self-signed certs locally:
$env:NODE_TLS_REJECT_UNAUTHORIZED=0; npx @mcpjam/inspector@latest -v
NODE_TLS_REJECT_UNAUTHORIZED=0 npx @mcpjam/inspector@latest -v
Authentication is a little bit flakey, but the OAuth Debugger works great.
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/mcpand proxy it to/my-mcp-server/.well-known/oauth-protected-resource/mcp. Now Claude.ai authentication works.
To install local MCP servers (stdio), we can easily add them to theclaude_desktop_config.jsonlike 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.
$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\"}"
Ifset NODE_OPTIONS=--use-system-cadoes 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 theclaude_desktop_config.jsonit 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 }
{ "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 atestTransport, but not fed forward into the actual transport inconnectToRemoteServer():
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 withResource metadata is remembered throughout the entire login flow. #167. Until this is merged, we can to compilemcp-remotelocally 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 everywhere
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 rannpm link.
MCP support requires ChatGPT Plus. Then users can enable "Developer mode" (which is still in BETA) and create a new connector. Custom OAuthclient_idis not supported.
Adding a localhost hosted MCP server only resulted in "Error fetching OAuth configuration".
To better test the MCP servers of this project, we can use a local MCP host likenanobot. It seems to support OAuth and mcp-ui.
export OPENAI_API_KEY=sk-proj-... nanobot run ./nanobot.yaml
It 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: middleware
This is a web browser that enables your coding agent, such as Claude Code, to visit websites on your behalf and assist you in identifying bugs or creating UI test cases.
Create crafted UI components inspired by the best 21st.dev design engineers.
Bring agent evaluations, observability, and synthetic test set generation directly into your IDE for free with Galileo's new MCP server
An MCP server to help AI assistants to answer questions and generate AccelByte Extend SDK code more effectively .
MCP server for AI Diagram Maker — generate beautiful software engineering diagrams directly inside Cursor, Claude Desktop, Claude Code, or any MCP-compatible AI agent
ALAPI MCP Tools,Call hundreds of API interfaces via MCP
AI-powered SVG animation generator that transforms static files into animated SVG components using the Allyson platform
MCP server that gives AI assistants on-demand access to 1,500+ amCharts docs, ~300 code examples, and 1000+ class API references.
APIMatic MCP Server is used to validate OpenAPI specifications using APIMatic. The server processes OpenAPI files and returns validation summaries by leveraging APIMatic’s API.
One shared context layer for AI agents and humans — live API specs, DB schemas, and versioned contracts across repos so every agent and teammate works from the same source of truth.
Build and deploy full-stack Next.js apps with 98 tools for React, AWS, and MongoDB
Sign in to leave a review
Use Google, GitHub, or an email account so ratings stay tied to real people.
No reviews posted yet.





