197 lines · 6.0 KB · TypeScript
RawDownload
import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "@effect/platform";import { Schema } from "effect";import { ScopeId } from "@executor/sdk"; // Re-export for handler useexport { HttpApiSchema }; // ---------------------------------------------------------------------------// Params// --------------------------------------------------------------------------- const scopeIdParam = HttpApiSchema.param("scopeId", ScopeId); // ---------------------------------------------------------------------------// Auth payload (only for remote)// --------------------------------------------------------------------------- const AuthPayload = Schema.Union(  Schema.Struct({ kind: Schema.Literal("none") }),  Schema.Struct({    kind: Schema.Literal("header"),    headerName: Schema.String,    secretId: Schema.String,    prefix: Schema.optional(Schema.String),  }),  Schema.Struct({    kind: Schema.Literal("oauth2"),    accessTokenSecretId: Schema.String,    refreshTokenSecretId: Schema.NullOr(Schema.String),    tokenType: Schema.optional(Schema.String),    expiresAt: Schema.NullOr(Schema.Number),    scope: Schema.NullOr(Schema.String),  }),); const StringMap = Schema.Record({ key: Schema.String, value: Schema.String }); // ---------------------------------------------------------------------------// Add source — discriminated union on transport// --------------------------------------------------------------------------- const AddRemoteSourcePayload = Schema.Struct({  transport: Schema.Literal("remote"),  name: Schema.String,  endpoint: Schema.String,  remoteTransport: Schema.optional(    Schema.Literal("streamable-http", "sse", "auto"),  ),  namespace: Schema.optional(Schema.String),  queryParams: Schema.optional(StringMap),  headers: Schema.optional(StringMap),  auth: Schema.optional(AuthPayload),}); const AddStdioSourcePayload = Schema.Struct({  transport: Schema.Literal("stdio"),  name: Schema.String,  command: Schema.String,  args: Schema.optional(Schema.Array(Schema.String)),  env: Schema.optional(StringMap),  cwd: Schema.optional(Schema.String),  namespace: Schema.optional(Schema.String),}); const AddSourcePayload = Schema.Union(  AddRemoteSourcePayload,  AddStdioSourcePayload,); // ---------------------------------------------------------------------------// Other payloads// --------------------------------------------------------------------------- const ProbeEndpointPayload = Schema.Struct({  endpoint: Schema.String,}); const ProbeEndpointResponse = Schema.Struct({  connected: Schema.Boolean,  requiresOAuth: Schema.Boolean,  name: Schema.String,  namespace: Schema.String,  toolCount: Schema.NullOr(Schema.Number),  serverName: Schema.NullOr(Schema.String),}); const NamespacePayload = Schema.Struct({  namespace: Schema.String,}); const StartOAuthPayload = Schema.Struct({  endpoint: Schema.String,  redirectUrl: Schema.String,  queryParams: Schema.optional(Schema.NullOr(StringMap)),}); const CompleteOAuthPayload = Schema.Struct({  state: Schema.String,  code: Schema.optional(Schema.String),  error: Schema.optional(Schema.String),}); const OAuthCallbackParams = Schema.Struct({  state: Schema.String,  code: Schema.optional(Schema.String),  error: Schema.optional(Schema.String),  error_description: Schema.optional(Schema.String),}); const HtmlResponse = HttpApiSchema.Text({ contentType: "text/html" }); // ---------------------------------------------------------------------------// Responses// --------------------------------------------------------------------------- const AddSourceResponse = Schema.Struct({  toolCount: Schema.Number,  namespace: Schema.String,}); const RefreshSourceResponse = Schema.Struct({  toolCount: Schema.Number,}); const RemoveSourceResponse = Schema.Struct({  removed: Schema.Boolean,}); const StartOAuthResponse = Schema.Struct({  sessionId: Schema.String,  authorizationUrl: Schema.String,}); const CompleteOAuthResponse = Schema.Struct({  accessTokenSecretId: Schema.String,  refreshTokenSecretId: Schema.NullOr(Schema.String),  tokenType: Schema.String,  expiresAt: Schema.NullOr(Schema.Number),  scope: Schema.NullOr(Schema.String),}); // ---------------------------------------------------------------------------// Error// --------------------------------------------------------------------------- const McpApiError = Schema.Struct({  message: Schema.String,}).annotations(HttpApiSchema.annotations({ status: 400 })); // ---------------------------------------------------------------------------// Group// --------------------------------------------------------------------------- export class McpGroup extends HttpApiGroup.make("mcp")  .add(    HttpApiEndpoint.post("probeEndpoint")`/scopes/${scopeIdParam}/mcp/probe`      .setPayload(ProbeEndpointPayload)      .addSuccess(ProbeEndpointResponse)      .addError(McpApiError),  )  .add(    HttpApiEndpoint.post("addSource")`/scopes/${scopeIdParam}/mcp/sources`      .setPayload(AddSourcePayload)      .addSuccess(AddSourceResponse)      .addError(McpApiError),  )  .add(    HttpApiEndpoint.post("removeSource")`/scopes/${scopeIdParam}/mcp/sources/remove`      .setPayload(NamespacePayload)      .addSuccess(RemoveSourceResponse)      .addError(McpApiError),  )  .add(    HttpApiEndpoint.post("refreshSource")`/scopes/${scopeIdParam}/mcp/sources/refresh`      .setPayload(NamespacePayload)      .addSuccess(RefreshSourceResponse)      .addError(McpApiError),  )  .add(    HttpApiEndpoint.post("startOAuth")`/scopes/${scopeIdParam}/mcp/oauth/start`      .setPayload(StartOAuthPayload)      .addSuccess(StartOAuthResponse)      .addError(McpApiError),  )  .add(    HttpApiEndpoint.post("completeOAuth")`/scopes/${scopeIdParam}/mcp/oauth/complete`      .setPayload(CompleteOAuthPayload)      .addSuccess(CompleteOAuthResponse)      .addError(McpApiError),  )  .add(    HttpApiEndpoint.get("oauthCallback")`/mcp/oauth/callback`      .setUrlParams(OAuthCallbackParams)      .addSuccess(HtmlResponse)      .addError(McpApiError),  )  .prefix("/v1") {}