MCP Experiments

Un servidor MCP experimental en dotnet que devuelve la hora actual, basado en el tutorial de Laurent Kempé.

Documentación

MCP Experiments

Estos experimentos de MCP son un campo de pruebas para comprender mejor la tecnología.

aspire run

Este sistema pone a disposición los siguientes endpoints a través de su gateway:

  • /my-mcp-server/mcp Servidor MCP experimental
  • /my-mcp-web-client Host MCP experimental
  • /identity Servidor de identidad

Desplegar como Azure Container Apps

$env:ASPIRE_CONTAINER_RUNTIME='podman'; aspire deploy
ASPIRE_CONTAINER_RUNTIME=podman aspire deploy

Clientes y compatibilidad

He probado la autenticación de MCP con los siguientes clientes.

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);

Funciona muy bien.

MCP Inspector

npx @modelcontextprotocol/inspector

⚠️ El inspector de MCP actualmente no sigue el resource_metadata del encabezado de respuesta WWW-Authenticate para localizar los metadatos del recurso protegido según la Sección 5 de RFC9728 (El flujo OAuth no admite resourceMetadataUrl #576). En su lugar, sigue un conjunto de reglas codificadas o permutaciones para encontrarlo:

  1. http://localhost:5253/.well-known/oauth-protected-resource/my-mcp-server
  2. http://localhost:5253/.well-known/oauth-protected-resource
  3. http://localhost:5253/.well-known/oauth-authorization-server
  4. http://localhost:5253/.well-known/openid-configuration

Cuando el WWW-Authenticate devuelto contiene Bearer realm="McpAuth", resource_metadata="http://localhost:5253/my-mcp-server/.well-known/oauth-protected-resource", el inspector de MCP debería adquirir inmediatamente los metadatos del recurso protegido desde http://localhost:5253/my-mcp-server/.well-known/oauth-protected-resource. Si no se proporciona resource_metadata, entonces puede recurrir a probar permutaciones.

Podemos añadir un endpoint proxy a nivel raíz, que redirija la solicitud al subrecurso:

yarp.AddRoute("/.well-known/oauth-protected-resource/my-mcp-server/mcp", myMcpServer);

Ahora el inspector de MCP se conecta correctamente al servidor MCP con gateway en /my-mcp-sever.

MCPJam Inspector

npx @mcpjam/inspector@latest

Si lo ejecutas contra certificados autofirmados localmente:

$env:NODE_TLS_REJECT_UNAUTHORIZED=0; npx @mcpjam/inspector@latest -v
NODE_TLS_REJECT_UNAUTHORIZED=0 npx @mcpjam/inspector@latest -v

La autenticación es un poco inestable, pero el Depurador OAuth funciona muy bien.

Claude

Obtén la aplicación de escritorio desde Claude.

Web (Claude.ai)

Al igual que el inspector de MCP, Claude.ai no parece admitir PRM detrás de una ruta como /my-mcp-server/.well-known/oauth-protected-resource/mcp. Eso significa que necesitamos poner PRM disponible a nivel raíz como /.well-known/oauth-protected-resource/my-mcp-server/mcp y redirigirlo a /my-mcp-server/.well-known/oauth-protected-resource/mcp. Ahora la autenticación de Claude.ai funciona.

Escritorio

Para instalar servidores MCP locales (stdio), podemos añadirlos fácilmente al claude_desktop_config.json de esta manera:

{
    "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"
            ]
        }
    }
}

Los conectores personalizados como servidores MCP remotos también se pueden añadir, con un ClientId y Secret de OAuth. Sin embargo, los conectores personalizados intentan autenticarse en /authorize, no en el endpoint de autorización configurado en los metadatos del servidor de autorización configurado en los metadatos del recurso protegido del servidor MCP.

Podemos usar mcp-remote para eso. Por defecto utiliza Dynamic Client Registration y almacena sus credenciales de cliente en ~\.mcp-auth. Pero podemos proporcionar metadatos OAuth estáticos:

$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\"}"

Si set NODE_OPTIONS=--use-system-ca ya no funciona (--use-system-ca is not allowed in NODE_OPTIONS), considera $env:NODE_TLS_REJECT_UNAUTHORIZED = "0".

Powershell tiene un problema de escape, así que es mejor poner los datos OAuth en un archivo JSON separado y referenciarlo de esta manera:

npx mcp-remote 'http://localhost:5253/my-mcp-server' 63113 --static-oauth-client-info "@D:\McpExperiments\MyMCPServer.Sse\mcp-remote-oauth-client-info.json"

En el claude_desktop_config.json se ve así:

{
    "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
}

O mediante el script claude_desktop.cmd:

{
  "mcpServers": {
    "getVibe": {
      "command": "D:\\McpExperiments\\MyMCPServer.Sse\\claude_desktop.cmd"
    }
  }
}

Sin embargo, esto actualmente falla durante "Completando autorización" con un 404. ¿Qué endpoint está intentando llamar? Los metadatos del recurso protegido se detectan con un testTransport, pero no se transmiten al transporte real en 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
}

He propuesto la corrección con Los metadatos del recurso se recuerdan durante todo el flujo de inicio de sesión. #167. Hasta que se fusione, podemos compilar mcp-remote localmente y configurarlo así:

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

O sin npm link:

npx --package=/Users/Manuel.Naujoks/Projects/mcp-remote mcp-remote https://…

Asegúrate de que tu instancia de Claude Desktop no use su Node.js integrado, sino que use la versión de Node.js de tu sistema operativo. En Configuración / Extensiones / Configuración avanzada deberías ver la misma versión de Node.js que usaste cuando ejecutaste npm link.

ChatGPT

El soporte de MCP requiere ChatGPT Plus. Luego los usuarios pueden habilitar el "Modo desarrollador" (que aún está en BETA) y crear un nuevo conector. El client_id OAuth personalizado no es compatible.

Añadir un servidor MCP alojado en localhost solo resultó en "Error al obtener la configuración OAuth".

Nanobot

Para probar mejor los servidores MCP de este proyecto, podemos usar un host MCP local como nanobot. Parece admitir OAuth y mcp-ui.

export OPENAI_API_KEY=sk-proj-...
nanobot run ./nanobot.yaml

Parece requerir client_secret y auth_endpoint, aunque la configuración del cliente no requiere un secreto y el endpoint de autorización se puede determinar según PRM y los metadatos del servidor de autorización.

Sin embargo, nanobot aún falla con un error extraño:

failed to setup auth: failed to create oauth proxy: invalid mode: middleware

Recursos