kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
feat: WIP kittens
rodzic
67f564bff8
commit
b0d3dcf589
|
@ -34,9 +34,9 @@
|
|||
"@agentic/platform-types": "workspace:*",
|
||||
"@agentic/platform-validators": "workspace:*",
|
||||
"@hono/zod-validator": "catalog:",
|
||||
"@modelcontextprotocol/sdk": "catalog:",
|
||||
"eventid": "catalog:",
|
||||
"hono": "catalog:",
|
||||
"@modelcontextprotocol/sdk": "catalog:",
|
||||
"type-fest": "catalog:"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -11,13 +11,15 @@ export async function enforceRateLimit(
|
|||
method,
|
||||
pathname
|
||||
}: {
|
||||
id: string
|
||||
id?: string
|
||||
interval: number
|
||||
maxPerInterval: number
|
||||
method: string
|
||||
pathname: string
|
||||
}
|
||||
) {
|
||||
assert(id, 400, 'Unauthenticated requests must have a valid IP address')
|
||||
|
||||
// TODO
|
||||
assert(ctx, 500, 'not implemented')
|
||||
assert(id, 500, 'not implemented')
|
||||
|
|
|
@ -2,7 +2,7 @@ import { assert } from '@agentic/platform-core'
|
|||
|
||||
import type { AdminConsumer, Context } from './types'
|
||||
|
||||
export async function getConsumer(
|
||||
export async function getAdminConsumer(
|
||||
ctx: Context,
|
||||
token: string
|
||||
): Promise<AdminConsumer> {
|
|
@ -4,7 +4,7 @@ import { parseFaasIdentifier } from '@agentic/platform-validators'
|
|||
|
||||
import type { Context } from './types'
|
||||
|
||||
export async function getDeployment(
|
||||
export async function getAdminDeployment(
|
||||
ctx: Context,
|
||||
identifier: string
|
||||
): Promise<{ deployment: AdminDeployment; toolPath: string }> {
|
|
@ -2,8 +2,9 @@ import type { PricingPlan, RateLimit } from '@agentic/platform-types'
|
|||
import { assert } from '@agentic/platform-core'
|
||||
|
||||
import type { AdminConsumer, Context, ResolvedOriginRequest } from './types'
|
||||
import { getConsumer } from './get-consumer'
|
||||
import { getDeployment } from './get-deployment'
|
||||
import { enforceRateLimit } from './enforce-rate-limit'
|
||||
import { getAdminConsumer } from './get-admin-consumer'
|
||||
import { getAdminDeployment } from './get-admin-deployment'
|
||||
import { getTool } from './get-tool'
|
||||
import { updateOriginRequest } from './update-origin-request'
|
||||
|
||||
|
@ -23,8 +24,13 @@ export async function resolveOriginRequest(
|
|||
|
||||
const { search, pathname } = requestUrl
|
||||
const method = req.method.toLowerCase()
|
||||
const requestPathParts = pathname.split('/')
|
||||
const requestPath =
|
||||
requestPathParts[0] === 'mcp'
|
||||
? requestPathParts.slice(1).join('/')
|
||||
: pathname
|
||||
|
||||
const { deployment, toolPath } = await getDeployment(ctx, pathname)
|
||||
const { deployment, toolPath } = await getAdminDeployment(ctx, requestPath)
|
||||
|
||||
const tool = getTool({
|
||||
method,
|
||||
|
@ -50,7 +56,7 @@ export async function resolveOriginRequest(
|
|||
.trim()
|
||||
|
||||
if (token) {
|
||||
consumer = await getConsumer(ctx, token)
|
||||
consumer = await getAdminConsumer(ctx, token)
|
||||
assert(consumer, 401, `Invalid auth token "${token}"`)
|
||||
assert(
|
||||
consumer.isStripeSubscriptionActive,
|
||||
|
@ -155,12 +161,11 @@ export async function resolveOriginRequest(
|
|||
}
|
||||
}
|
||||
|
||||
// enforce requests rate limits
|
||||
if (rateLimit) {
|
||||
await enforceRateLimit(ctx, {
|
||||
id: consumer ? consumer.id : ip,
|
||||
duration: rateLimit.interval * 1000,
|
||||
max: rateLimit.maxPerInterval,
|
||||
id: consumer?.id ?? ip,
|
||||
interval: rateLimit.interval * 1000,
|
||||
maxPerInterval: rateLimit.maxPerInterval,
|
||||
method,
|
||||
pathname
|
||||
})
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
||||
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js'
|
||||
|
||||
import type { Context, ResolvedOriginRequest } from './lib/types'
|
||||
|
||||
// TODO: https://github.com/modelcontextprotocol/servers/blob/8fb7bbdab73eddb42aba72e8eab81102efe1d544/src/everything/sse.ts
|
||||
// TODO: https://github.com/cloudflare/agents
|
||||
|
||||
const transports: Map<string, SSEServerTransport> = new Map<
|
||||
string,
|
||||
SSEServerTransport
|
||||
>()
|
||||
|
||||
export async function handleMCPRequest(
|
||||
ctx: Context,
|
||||
resolvedOriginRequest: ResolvedOriginRequest
|
||||
) {
|
||||
const serverTransport = new SSEServerTransport()
|
||||
const server = new McpServer({
|
||||
name: 'weather',
|
||||
version: '1.0.0',
|
||||
capabilities: {
|
||||
resources: {},
|
||||
tools: {}
|
||||
}
|
||||
})
|
||||
}
|
|
@ -62,6 +62,17 @@ export default {
|
|||
const resolvedOriginRequest = await resolveOriginRequest(ctx)
|
||||
|
||||
try {
|
||||
switch (resolvedOriginRequest.deployment.originAdapter.type) {
|
||||
case 'openapi':
|
||||
break
|
||||
|
||||
case 'raw':
|
||||
break
|
||||
|
||||
case 'mcp':
|
||||
break
|
||||
}
|
||||
|
||||
const originReqCacheKey = await getOriginRequestCacheKey(originReq)
|
||||
originStartTime = Date.now()
|
||||
|
||||
|
|
24
readme.md
24
readme.md
|
@ -7,8 +7,6 @@
|
|||
|
||||
## TODO
|
||||
|
||||
- **api gateway**
|
||||
- signed requests
|
||||
- **webapp**
|
||||
- end-to-end working examples
|
||||
- raw
|
||||
|
@ -25,7 +23,7 @@
|
|||
- (openauth password emails and `sendCode`)
|
||||
- stripe-related billing emails
|
||||
- auth
|
||||
- custom auth pages
|
||||
- custom auth pages for `openauth`
|
||||
- re-add support for teams / organizations
|
||||
- consider switching to [consola](https://github.com/unjs/consola) for logging?
|
||||
- consider switching to `bun` (for `--hot` reloading!!)
|
||||
|
@ -36,11 +34,23 @@
|
|||
- validate stability of pricing plan slugs across deployments
|
||||
- same for pricing plan line-items
|
||||
- replace `ms` package
|
||||
- API gateway MCP server vs OpenAPI API gateway
|
||||
- share hono middleware and utils across apps/api and apps/gateway
|
||||
- or combine these together? ehhhh
|
||||
- add username / team name blacklist
|
||||
- admin, internal, mcp, etc
|
||||
- admin, internal, mcp, sse, etc
|
||||
- **API gateway**
|
||||
- share hono middleware and utils across apps/api and apps/gateway
|
||||
- or combine these together? ehhhh
|
||||
- MCP server vs REST gateway on public and internal sides
|
||||
- RAW: `METHOD gateway.agentic.so/deploymentIdentifier/<pathname>`
|
||||
- => Raw HTTP: `METHOD originUrl/<pathname>` simple HTTP proxy request
|
||||
- REST: `POST gateway.agentic.so/deploymentIdentifier/toolName`
|
||||
- => MCP: `MCPClient.callTool` with JSON body parameters
|
||||
- => OpenAPI: `GET/POST/ETC originUrl/toolName` operation with transformed JSON body params
|
||||
- MCP: `mcp.agentic.so/deploymentIdentifier/sse` MCP server
|
||||
- => MCP: `MCPClient.callTool` just proxying tool call
|
||||
- => OpenAPI: `GET/POST/ETC originUrl/toolName` operation with transformed tool params
|
||||
- add support for caching
|
||||
- add support for custom headers on response
|
||||
- signed requests
|
||||
|
||||
## License
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue