From 449e927bb2c8294f3aab909ed8005cc68460cfb9 Mon Sep 17 00:00:00 2001 From: Travis Fischer Date: Sat, 14 Jun 2025 02:31:20 +0700 Subject: [PATCH] chore: improve claude.md --- CLAUDE.md | 23 ++++++++++++---------- packages/types/src/tools.ts | 13 +++++------- packages/validators/src/index.ts | 1 + packages/validators/src/validators.test.ts | 11 +++++++++++ packages/validators/src/validators.ts | 5 +++++ readme.md | 5 ++--- 6 files changed, 37 insertions(+), 21 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 301bb410..bf7853a7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -12,7 +12,7 @@ The platform consists of: - **API Service** (`apps/api/`) - Internal platform API with authentication, billing, and resource management - **Gateway Service** (`apps/gateway/`) - Cloudflare Worker that proxies requests to origin MCP/OpenAPI services -- **E2E Tests** (`apps/e2e/`) - End-to-end test suite for HTTP and MCP interfaces +- **E2E Tests** (`apps/e2e/`) - End-to-end test suite for HTTP and MCP gateway requests - **Shared Packages** (`packages/`) - Common utilities, types, validators, and configuration The gateway accepts requests at `https://gateway.agentic.so/deploymentIdentifier/toolName` for REST or `https://gateway.agentic.so/deploymentIdentifier/mcp` for MCP. @@ -119,27 +119,30 @@ All packages must follow these `package.json` rules: - Use TypeScript's utility types (e.g., `Partial`, `Pick`, `Omit`) to manipulate existing types - Create custom types for complex data structures used throughout the application - If possible, avoid using `any`/`unknown` or casting values like `(value as any)` in TypeScript outside of test files e.g. `*.test.ts` or test fixtures e.g. `**/test-data.ts`. -- Don't rely on `typeof`, `ReturnType<>`, `Awaited<>`, etc for complex type inference (it's ok for simple types) +- Try not to rely on `typeof`, `ReturnType<>`, `Awaited<>`, etc for complex type inference (it's ok for simple types) - You can use `as const` as needed for better type inference - Functions should accept an object parameter instead of multiple parameters - - Good examples: + - GOOD examples: ```ts function myFunction({ foo, bar }: { foo: boolean; bar: string }) {} function VideoPlayer({ sid }: { sid: string }) {} ``` - - Bad examples: + - BAD examples: ```ts function myFunction(foo: boolean, bar: string, baz: number) {} ``` - Arguments should generally be destructured in the function definition, not the function body. - - Good example: + - GOOD example: ```ts function myFunction({ foo, bar }: { foo: boolean; bar: string }) {} + function exampleWithOptionalParams({ + foo = 'example' + }: { foo?: string } = {}) {} ``` - - Bad example: + - BAD example: ```ts - function myFunction(args: { foo: boolean; bar: string }) { - const { foo, bar } = args + function myFunction(opts: { foo: boolean; bar: string }) { + const { foo, bar } = opts } ``` - Zod should be used to parse untrusted data, but not for data that is trusted like function arguments @@ -192,8 +195,8 @@ Comments should be used to document and explain code. They should complement the - **All unit tests should use Vitest** - DO NOT attempt to install or use other testing libraries like Jest - Test files should be named `[target].test.ts` and placed in the same directory as the code they are testing (NOT a separate directory) - - Good example: `src/my-file.ts` and `src/my-file.test.ts` - - Bad example: `src/my-file.ts` and `src/test/my-file.test.ts` or `test/my-file.test.ts` or `src/__tests__/my-file.test.ts` + - GOOD example: `src/my-file.ts` and `src/my-file.test.ts` + - BAD example: `src/my-file.ts` and `src/test/my-file.test.ts` or `test/my-file.test.ts` or `src/__tests__/my-file.test.ts` - Tests should be run with `pnpm test:unit` - You may use `any`/`unknown` in test files (such as `*.test.ts`) or test fixtures (like `**/test-data.ts`) to facilitate mocking or stubbing external modules or partial function arguments, referencing the usage guidelines in the TypeScript section. - Frontend react code does not need unit tests diff --git a/packages/types/src/tools.ts b/packages/types/src/tools.ts index 6fb00899..35493bad 100644 --- a/packages/types/src/tools.ts +++ b/packages/types/src/tools.ts @@ -1,17 +1,14 @@ -import { toolNameRe } from '@agentic/platform-validators' +import { isToolNameAllowed, toolNameRe } from '@agentic/platform-validators' import { z } from '@hono/zod-openapi' import { pricingPlanSlugSchema } from './pricing' import { rateLimitSchema } from './rate-limit' -// TODO: add more reserved tool names? -// TODO: if we separate mcp endpoint from REST endpoint, we may be able to have -// tools named `mcp`. would be nice not to impose a blacklist. -const toolNameBlacklist = new Set(['mcp']) - /** * Agentic tool name. * + * Follows OpenAI/Anthropic/Gemini function calling naming conventions. + * * @example `"get_weather"` * @example `"searchGoogle"` * @example `"get_user_info2"` @@ -21,9 +18,9 @@ export const toolNameSchema = z .nonempty() .regex(toolNameRe) .refine( - (name) => !toolNameBlacklist.has(name), + (name) => isToolNameAllowed(name), (name) => ({ - message: `Tool name is reserved: "${name}"` + message: `Tool name "${name}" is reserved; please choose a different name.` }) ) .describe('Agentic tool name') diff --git a/packages/validators/src/index.ts b/packages/validators/src/index.ts index 32a84b30..d65dac14 100644 --- a/packages/validators/src/index.ts +++ b/packages/validators/src/index.ts @@ -2,5 +2,6 @@ export * from './namespace-blacklist' export * from './parse-deployment-identifier' export * from './parse-project-identifier' export * from './parse-tool-identifier' +export * from './tool-name-blacklist' export type * from './types' export * from './validators' diff --git a/packages/validators/src/validators.test.ts b/packages/validators/src/validators.test.ts index ae3679a1..72638afd 100644 --- a/packages/validators/src/validators.test.ts +++ b/packages/validators/src/validators.test.ts @@ -2,6 +2,7 @@ import { expect, test } from 'vitest' import { isNamespaceAllowed, + isToolNameAllowed, isValidDeploymentHash, isValidDeploymentIdentifier, isValidEmail, @@ -177,3 +178,13 @@ test('isValidToolName failure', () => { ) ).toBe(false) }) + +test('isToolNameAllowed', () => { + expect(isToolNameAllowed('foo')).toBe(true) + expect(isToolNameAllowed('tool_name')).toBe(true) + expect(isToolNameAllowed('searchGoogle')).toBe(true) + expect(isToolNameAllowed('mcp')).toBe(false) + expect(isToolNameAllowed('sse')).toBe(false) + expect(isToolNameAllowed()).toBe(false) + expect(isToolNameAllowed('')).toBe(false) +}) diff --git a/packages/validators/src/validators.ts b/packages/validators/src/validators.ts index abccc7ba..40278c62 100644 --- a/packages/validators/src/validators.ts +++ b/packages/validators/src/validators.ts @@ -5,6 +5,7 @@ import type { ParseIdentifierOptions } from './types' import { namespaceBlacklist } from './namespace-blacklist' import { parseDeploymentIdentifier } from './parse-deployment-identifier' import { parseProjectIdentifier } from './parse-project-identifier' +import { toolNameBlacklist } from './tool-name-blacklist' export const namespaceRe = /^[a-z0-9-]{1,256}$/ export const passwordRe = /^.{3,1024}$/ @@ -72,6 +73,10 @@ export function isValidToolName(value?: string): boolean { return !!value && toolNameRe.test(value) } +export function isToolNameAllowed(value?: string): boolean { + return !!value && isValidToolName(value) && !toolNameBlacklist.has(value) +} + export function isValidCuid(value?: string): boolean { return !!value && isCuid(value) } diff --git a/readme.md b/readme.md index d33a3766..898a3c68 100644 --- a/readme.md +++ b/readme.md @@ -7,8 +7,8 @@ ## API Gateway -- **REST**: `GET/POST` `https://gateway.agentic.so/deploymentIdentifier/toolName` -- **MCP**: `https://gateway.agentic.so/deploymentIdentifier/mcp` +- **MCP**: `https://gateway.agentic.so/@{username}/{project-name}/mcp` +- **HTTP**: `GET/POST` `https://gateway.agentic.so/@{username}/{project-name}/{tool-name}` ## TODO: MVP @@ -24,7 +24,6 @@ - oauth flow - https://docs.scalekit.com/guides/mcp/oauth - **test usage tracking and reporting** - - disallow `mcp` and `sse` as tool names or figure out a different workaround - docs - main readme - sub readmes