1- { Glob } from bun
2- path from node:path
3-
41{ z, type ZodType, type ZodRawShape, type Primitive } from zod
52type { ToolAnnotations, ServerRequest, ServerNotification } from @modelcontextprotocol/sdk/types.js
63type { McpServer } from @modelcontextprotocol/sdk/server/mcp.js
@@ -17,15 +14,19 @@ export TSerializable<T> ::= {
1714}
1815
1916export ToolDeclarationConfig ::= {
20- title? : string
21- description? : string
22- inputSchema? : ZodRawShape extends infer TInputSchema ? TInputSchema : never
17+ title: string
18+ description: string
19+ inputSchema: ZodRawShape extends infer TInputSchema ? TInputSchema : never
2320 outputSchema?: ZodRawShape extends infer TOutputSchema ? TOutputSchema : never
2421 annotations?: ToolAnnotations
2522}
2623
2724export ToolDeclarationRunCallback<TConfig extends ToolDeclarationConfig = ToolDeclarationConfig, TConstructor extends new (...args: any[]) => any = new () => any> ::=
28- (@: ToolDeclaration<TConfig, TConstructor> & InstanceType<TConstructor>, args: TInferedSchema<TConfig["inputSchema"]>, extra: RequestHandlerExtra<ServerRequest, ServerNotification>) -> Promise<
25+ (
26+ @: ToolDeclaration<TConfig, TConstructor> & InstanceType<TConstructor>,
27+ args: TInferedSchema<TConfig["inputSchema"] extends infer TInputSchema ? TInputSchema : never>,
28+ extra: RequestHandlerExtra<ServerRequest, ServerNotification>
29+ ) -> Promise<
2930 TSerializable<TInferedSchema<TConfig["outputSchema"]>> | TSerializable<TInferedSchema<TConfig["outputSchema"]>>[] | null
3031 >
3132
@@ -63,36 +64,24 @@ safeActionCallToOutput := <T extends ToolDeclaration>(member: T) ->
6364
6465// All tools are loaded via a glob scan, so we can just iterate over the files and import them
6566// This means to create new tools you just need to create a new file in `src/tools`
66- export registerTools := (server: McpServer) -> {
67- // Prepare to register tools
68- { dirname } := import.meta
69- civetGlob := new Glob "**/*.civet"
70- toolsPath := path.join dirname, 'tools'
71-
67+ export registerTools := <TConfig extends ToolDeclarationConfig, T extends ToolDeclaration<TConfig>>(tools: Record<string, T>) -> (server: McpServer) -> {
7268 // Register tools based on the glob pattern
73- for await file of civetGlob.scan toolsPath {
74- // Import the tool declaration module file
75- absoluteToolPath := path.join toolsPath, file
76- toolDeclarationModule := await import absoluteToolPath
77- toolDeclarationModuleExportedMembers := Object.values toolDeclarationModule
78-
69+ for await member of Object.values tools {
7970 // For each exported member, if it's a tool declaration, register it with the server
80- for member of toolDeclarationModuleExportedMembers {
81- // Filter out exports that aren't tool declarations
82- unless member instanceof ToolDeclaration {
83- continue
84- }
85-
86- // Register the tool with the server
87- server.registerTool(
88- member.name,
89- member.config,
90- // Wrap the run call in a try/catch and return the result in the MCP format
91- // @ts-expect-error -- The types are all right here, but the SDK won't know that a `Promise` of the
92- // `ToolCallback` is a valid `ToolCallback` (because promises are flattened)
93- safeActionCallToOutput member
94- )
71+ // Filter out exports that aren't tool declarations
72+ unless member instanceof ToolDeclaration {
73+ continue
9574 }
75+
76+ // Register the tool with the server
77+ server.registerTool(
78+ member.name,
79+ member.config,
80+ // Wrap the run call in a try/catch and return the result in the MCP format
81+ // @ts-expect-error -- The types are all right here, but the SDK won't know that a `Promise` of the
82+ // `ToolCallback` is a valid `ToolCallback` (because promises are flattened)
83+ safeActionCallToOutput member
84+ )
9685 }
9786
9887 // Return the server to allow for chaining
0 commit comments