McpServer: middleware and visibility can't use per-request services from HttpRouter middleware under layerHttp
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Aptitud para principiantes
- 55/100
- Tipo de issue
- Error
- Claridad
- Bastante claro
- Estado de actividad
- Activo
- Stack tecnológico
- typescript
- Área
- backend-api-design
Línea de trabajo
Start with MiddlewareLayer and its McpRequest.From<"Requires", ...> layer type, then compare how middleware requirements are handled by layerHttp, layer, and layerStdio. The report says the runtime already forwards these dependencies through layerHttp; verify the behavior with the described visibility and tool-call cases. Done when middleware and visibility can use HttpRouter per-request services through layerHttp, while unmet requirements remain visible for layer and layerStdio.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
On v4/next-minor (pkg.pr.new 7ce7d03), tools can depend on per-request services provided by HttpRouter middleware: layerHttp converts the remaining McpRequest.From<"Requires", R> into HttpRouter.Request.From<"Requires", R>. MCP middleware and visibility checks can't. MiddlewareLayer turns any requirement outside TransportServices into MissingRequestDependencies, so it can only be satisfied by .combine or the transport.
class CurrentUser extends Context.Service<CurrentUser, { readonly id: number }>()("CurrentUser") {}
// HTTP auth stays at the HTTP layer: OAuth discovery and refresh need a 401 with WWW-Authenticate,
// and MCP middleware never runs for initialize/ping
const Auth = HttpRouter.middleware<{ provides: CurrentUser }>()(/* bearer token -> user */)
const Policy = McpServer.visibility(
Effect.succeed(({ target }) =>
Effect.gen(function* () {
const user = yield* CurrentUser
return canUse(user, target)
})
)
)
Policy.layer
// ^? MissingRequestDependencies<CurrentUser>, although Auth provides CurrentUser to every request under layerHttp
The workaround is an MCP middleware that re-provides what is already on the fiber:
const Bridge = McpServer.middleware<{ provides: CurrentUser }>()((effect) =>
Effect.gen(function* () {
const user = yield* Effect.serviceOption(CurrentUser)
if (Option.isNone(user)) return yield* Effect.die(new Error("missing HTTP auth"))
return yield* effect.pipe(CurrentUser.provide(user.value))
})
)
Policy.combine(Bridge).layer
Doing the authentication itself in a combined MCP middleware would mean resolving the token and user a second time on every request.
Proposal
Drop the conditional and always put the per-request requirements in the layer input, as registrations already do. layerHttp then forwards them to HttpRouter, while layer / layerStdio still surface them as unmet requirements:
type MiddlewareLayer<Config extends MiddlewareConfig, R> = Layer.Layer<
McpRequest.From<"Requires", Config["provides"]>,
Config["layerError"],
R | Config["layerRequires"] | McpRequest.From<"Requires", Config["requires"]>
>
The runtime already handles this. With only the .d.ts patched and the bridge removed, through layerHttp + HttpRouter.toWebHandler:
tools/listhides the tool the policy rejects- the visible tool receives
CurrentUser - calling the hidden tool returns
-32602 Tool '…' not found
Trade-off: an unmet requirement then shows up as a missing layer requirement at the server instead of the named MissingRequestDependencies at .layer. Happy to open a PR if this direction is fine.
- Lenguaje dominante
- TypeScript
- Estrellas
- 16.7k
- Forks
- 808
- Merge medio
- 11 h 24 min
- PR fusionados (30 d)
- 848
Preparar el entorno
Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de Effect-TS/effect
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 35/100
Los mantenedores suelen responder en 1 día
-
AI providers: tool results cannot carry images because non-string results are JSON.stringify'dPosiblemente ocupada @nmnmcc la tomó hoy. Abierto
Dificultad 5/5 Más de una semana Aptitud para principiantes 35/100
Effect-TS/effect#9857 · 2 comentarios ·
Los mantenedores suelen responder en 1 día
-
`Schema.Literals`: add `omit`, the complement of `pick`Posiblemente ocupada @effect-bot la tomó hace 1 día. Abiertoenhancement Needs Evaluation
Dificultad 3/5 1-2 días Aptitud para principiantes 35/100
Los mantenedores suelen responder en 1 día
-
Support the `openapi-3.0` target in `Schema.toStandardJSONSchemaV1`Posiblemente ocupada @MichaelDeBoey la tomó hace 1 día. Abiertoenhancement Needs Evaluation
Dificultad 4/5 3-5 días Aptitud para principiantes 48/100
Effect-TS/effect#9764 · 3 comentarios ·
Los mantenedores suelen responder en 1 día
-
RpcClient.layerProtocolWorker: what's the equivalent of Piscina's abortable tasks? (terminate a stuck worker on interrupt, control respawn)Posiblemente ocupada @effect-bot la tomó hace 7 días. Abierto
Effect-TS/effect#9332 · 1 comentario · 1 asignado ·
Los mantenedores suelen responder en 1 día
Todos los issues de Effect-TS/effect
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
braintrustdata/braintrust-sdk-javascript#2659 ·
Los mantenedores suelen responder en 1 día
-
body-parser 2.3.0 in the published ai-dial-chat-bff image is vulnerable (CVE-2026-111181, HIGH)Posiblemente ocupada @illya-havsiyevych la tomó hoy. Abiertobug
Dificultad 1/5 1-3 horas Aptitud para principiantes 87/100
epam/ai-dial-chat#9566 ·
Los mantenedores suelen responder en 1 día
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 83/100
Los mantenedores suelen responder en 1 día
-
はさみアイコンを修正するAbiertobug
Dificultad 1/5 Menos de una hora Aptitud para principiantes 68/100
-
resource.reload() while params is in error switches the resource to 'idle' instead of retryingAbiertoarea: core
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Los mantenedores suelen responder en 1 día