fix(httpapi): return mcp server not found errors (#28817)
This commit is contained in:
@@ -140,6 +140,15 @@ export class PermissionNotFoundError extends Schema.TaggedErrorClass<PermissionN
|
||||
{ httpApiStatus: 404 },
|
||||
) {}
|
||||
|
||||
export class McpServerNotFoundError extends Schema.TaggedErrorClass<McpServerNotFoundError>()(
|
||||
"McpServerNotFoundError",
|
||||
{
|
||||
name: Schema.String,
|
||||
message: Schema.String,
|
||||
},
|
||||
{ httpApiStatus: 404 },
|
||||
) {}
|
||||
|
||||
export class ApiNotFoundError extends Schema.ErrorClass<ApiNotFoundError>("NotFoundError")(
|
||||
{
|
||||
name: Schema.Literal("NotFoundError"),
|
||||
|
||||
@@ -2,6 +2,7 @@ import { MCP } from "@/mcp"
|
||||
import { ConfigMCP } from "@/config/mcp"
|
||||
import { Schema } from "effect"
|
||||
import { HttpApi, HttpApiEndpoint, HttpApiError, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"
|
||||
import { McpServerNotFoundError } from "../errors"
|
||||
import { Authorization } from "../middleware/authorization"
|
||||
import { InstanceContextMiddleware } from "../middleware/instance-context"
|
||||
import { WorkspaceRoutingMiddleware, WorkspaceRoutingQuery } from "../middleware/workspace-routing"
|
||||
@@ -67,7 +68,7 @@ export const McpApi = HttpApi.make("mcp")
|
||||
params: { name: Schema.String },
|
||||
query: WorkspaceRoutingQuery,
|
||||
success: described(AuthStartResponse, "OAuth flow started"),
|
||||
error: [UnsupportedOAuthError, HttpApiError.NotFound],
|
||||
error: [UnsupportedOAuthError, McpServerNotFoundError],
|
||||
}).annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "mcp.auth.start",
|
||||
@@ -80,7 +81,7 @@ export const McpApi = HttpApi.make("mcp")
|
||||
query: WorkspaceRoutingQuery,
|
||||
payload: AuthCallbackPayload,
|
||||
success: described(MCP.Status, "OAuth authentication completed"),
|
||||
error: [HttpApiError.BadRequest, HttpApiError.NotFound],
|
||||
error: [HttpApiError.BadRequest, McpServerNotFoundError],
|
||||
}).annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "mcp.auth.callback",
|
||||
@@ -93,7 +94,7 @@ export const McpApi = HttpApi.make("mcp")
|
||||
params: { name: Schema.String },
|
||||
query: WorkspaceRoutingQuery,
|
||||
success: described(MCP.Status, "OAuth authentication completed"),
|
||||
error: [UnsupportedOAuthError, HttpApiError.NotFound],
|
||||
error: [UnsupportedOAuthError, McpServerNotFoundError],
|
||||
}).annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "mcp.auth.authenticate",
|
||||
@@ -105,7 +106,7 @@ export const McpApi = HttpApi.make("mcp")
|
||||
params: { name: Schema.String },
|
||||
query: WorkspaceRoutingQuery,
|
||||
success: described(AuthRemoveResponse, "OAuth credentials removed"),
|
||||
error: HttpApiError.NotFound,
|
||||
error: McpServerNotFoundError,
|
||||
}).annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "mcp.auth.remove",
|
||||
@@ -117,6 +118,7 @@ export const McpApi = HttpApi.make("mcp")
|
||||
params: { name: Schema.String },
|
||||
query: WorkspaceRoutingQuery,
|
||||
success: described(Schema.Boolean, "MCP server connected successfully"),
|
||||
error: McpServerNotFoundError,
|
||||
}).annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "mcp.connect",
|
||||
@@ -127,6 +129,7 @@ export const McpApi = HttpApi.make("mcp")
|
||||
params: { name: Schema.String },
|
||||
query: WorkspaceRoutingQuery,
|
||||
success: described(Schema.Boolean, "MCP server disconnected successfully"),
|
||||
error: McpServerNotFoundError,
|
||||
}).annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "mcp.disconnect",
|
||||
|
||||
@@ -2,6 +2,7 @@ import { MCP } from "@/mcp"
|
||||
import { Effect, Schema } from "effect"
|
||||
import { HttpApiBuilder, HttpApiError } from "effect/unstable/httpapi"
|
||||
import { InstanceHttpApi } from "../api"
|
||||
import { McpServerNotFoundError } from "../errors"
|
||||
import { AddPayload, AuthCallbackPayload, StatusMap, UnsupportedOAuthError } from "../groups/mcp"
|
||||
|
||||
export const mcpHandlers = HttpApiBuilder.group(InstanceHttpApi, "mcp", (handlers) =>
|
||||
@@ -20,38 +21,74 @@ export const mcpHandlers = HttpApiBuilder.group(InstanceHttpApi, "mcp", (handler
|
||||
})
|
||||
|
||||
const authStart = Effect.fn("McpHttpApi.authStart")(function* (ctx: { params: { name: string } }) {
|
||||
if (!(yield* mcp.supportsOAuth(ctx.params.name))) {
|
||||
return yield* new UnsupportedOAuthError({ error: `MCP server ${ctx.params.name} does not support OAuth` })
|
||||
}
|
||||
return yield* mcp.startAuth(ctx.params.name)
|
||||
return yield* Effect.gen(function* () {
|
||||
if (!(yield* mcp.supportsOAuth(ctx.params.name))) {
|
||||
return yield* new UnsupportedOAuthError({ error: `MCP server ${ctx.params.name} does not support OAuth` })
|
||||
}
|
||||
return yield* mcp.startAuth(ctx.params.name)
|
||||
}).pipe(
|
||||
Effect.catchTag("MCP.NotFoundError", (error) =>
|
||||
Effect.fail(new McpServerNotFoundError({ name: error.name, message: `MCP server not found: ${error.name}` })),
|
||||
),
|
||||
)
|
||||
})
|
||||
|
||||
const authCallback = Effect.fn("McpHttpApi.authCallback")(function* (ctx: {
|
||||
params: { name: string }
|
||||
payload: typeof AuthCallbackPayload.Type
|
||||
}) {
|
||||
return yield* mcp.finishAuth(ctx.params.name, ctx.payload.code)
|
||||
return yield* mcp
|
||||
.finishAuth(ctx.params.name, ctx.payload.code)
|
||||
.pipe(
|
||||
Effect.catchTag("MCP.NotFoundError", (error) =>
|
||||
Effect.fail(new McpServerNotFoundError({ name: error.name, message: `MCP server not found: ${error.name}` })),
|
||||
),
|
||||
)
|
||||
})
|
||||
|
||||
const authAuthenticate = Effect.fn("McpHttpApi.authAuthenticate")(function* (ctx: { params: { name: string } }) {
|
||||
if (!(yield* mcp.supportsOAuth(ctx.params.name))) {
|
||||
return yield* new UnsupportedOAuthError({ error: `MCP server ${ctx.params.name} does not support OAuth` })
|
||||
}
|
||||
return yield* mcp.authenticate(ctx.params.name)
|
||||
return yield* Effect.gen(function* () {
|
||||
if (!(yield* mcp.supportsOAuth(ctx.params.name))) {
|
||||
return yield* new UnsupportedOAuthError({ error: `MCP server ${ctx.params.name} does not support OAuth` })
|
||||
}
|
||||
return yield* mcp.authenticate(ctx.params.name)
|
||||
}).pipe(
|
||||
Effect.catchTag("MCP.NotFoundError", (error) =>
|
||||
Effect.fail(new McpServerNotFoundError({ name: error.name, message: `MCP server not found: ${error.name}` })),
|
||||
),
|
||||
)
|
||||
})
|
||||
|
||||
const authRemove = Effect.fn("McpHttpApi.authRemove")(function* (ctx: { params: { name: string } }) {
|
||||
const status = yield* mcp.status()
|
||||
if (!(ctx.params.name in status))
|
||||
return yield* new McpServerNotFoundError({
|
||||
name: ctx.params.name,
|
||||
message: `MCP server not found: ${ctx.params.name}`,
|
||||
})
|
||||
yield* mcp.removeAuth(ctx.params.name)
|
||||
return { success: true as const }
|
||||
})
|
||||
|
||||
const connect = Effect.fn("McpHttpApi.connect")(function* (ctx: { params: { name: string } }) {
|
||||
yield* mcp.connect(ctx.params.name)
|
||||
yield* mcp
|
||||
.connect(ctx.params.name)
|
||||
.pipe(
|
||||
Effect.catchTag("MCP.NotFoundError", (error) =>
|
||||
Effect.fail(new McpServerNotFoundError({ name: error.name, message: `MCP server not found: ${error.name}` })),
|
||||
),
|
||||
)
|
||||
return true
|
||||
})
|
||||
|
||||
const disconnect = Effect.fn("McpHttpApi.disconnect")(function* (ctx: { params: { name: string } }) {
|
||||
yield* mcp.disconnect(ctx.params.name)
|
||||
yield* mcp
|
||||
.disconnect(ctx.params.name)
|
||||
.pipe(
|
||||
Effect.catchTag("MCP.NotFoundError", (error) =>
|
||||
Effect.fail(new McpServerNotFoundError({ name: error.name, message: `MCP server not found: ${error.name}` })),
|
||||
),
|
||||
)
|
||||
return true
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user