Skip to main content
Glama

create_folder

Create a folder under a project root or knowledge base. Supports nested paths like 'notes/inbox' by creating intermediate directories. Idempotent: succeeds even if folder exists.

Instructions

Create a folder under a project root or the KB. Idempotent — creating an existing folder succeeds. Nested paths like notes/inbox create intermediates. REJECTS: empty names, null bytes, leading path separators, and any segment equal to .. (the call returns isError, no folder is touched). Side effect: a directory is mkdir'd on disk; no DB rows are written until a file lands inside. No external auth or rate limits. Returns {path, base_path}.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
project_idNoProject ID. Pass null or omit to create the folder under the KB.
nameYesFolder name (relative; supports nested paths via '/')

Implementation Reference

  • Core handler: creates a folder by resolving the path safely with assertPathInside, then calling mkdirSync with recursive: true. Returns the full path.
    export function createFolder(projectPath: string, folderName: string): string {
      const fullPath = assertPathInside(projectPath, folderName);
      mkdirSync(fullPath, { recursive: true });
      return fullPath;
    }
  • MCP tool registration using server.tool() with name 'create_folder', schema (project_id optional nullable int, name string), and handler that validates input, resolves base path, and delegates to core createFolder.
    server.tool(
      "create_folder",
      "Create a folder under a project root or the KB. Idempotent — creating an existing folder succeeds. Nested paths like `notes/inbox` create intermediates. REJECTS: empty names, null bytes, leading path separators, and any segment equal to `..` (the call returns isError, no folder is touched). Side effect: a directory is mkdir'd on disk; no DB rows are written until a file lands inside. No external auth or rate limits. Returns `{path, base_path}`.",
      {
        project_id: z.number().nullable().optional().describe("Project ID. Pass null or omit to create the folder under the KB."),
        name: z.string().describe("Folder name (relative; supports nested paths via '/')"),
      },
      async ({ project_id, name }) => {
        try {
          validateFolderName(name);
          const base = resolveFolderBase(project_id);
          const path = createFolder(base, name);
          return {
            content: [{ type: "text", text: JSON.stringify({ path, base_path: base }, null, 2) }],
          };
        } catch (e: any) {
          return {
            isError: true,
            content: [{ type: "text", text: JSON.stringify({ error: e?.message ?? String(e) }, null, 2) }],
          };
        }
      }
    );
  • Zod schema for create_folder: project_id (nullable optional number) and name (string) input parameters.
    {
      project_id: z.number().nullable().optional().describe("Project ID. Pass null or omit to create the folder under the KB."),
      name: z.string().describe("Folder name (relative; supports nested paths via '/')"),
    },
  • Validates folder name before calling createFolder: rejects empty/null, null bytes, leading separators, and '..' traversal segments.
    function validateFolderName(name: string): void {
      if (typeof name !== "string" || name.length === 0) {
        throw new Error("name must be a non-empty string");
      }
      if (name.includes("\0")) throw new Error("name contains null byte");
      if (name.startsWith("/") || name.startsWith("\\")) {
        throw new Error("name must not start with a path separator");
      }
      if (name.split(/[/\\]/).some((seg) => seg === "..")) {
        throw new Error("name must not contain '..' segments");
      }
    }
  • Resolves the base directory path for folder operations: KB data dir if project_id is null/undefined, or the project's registered path from the database.
    function resolveFolderBase(projectId: number | null | undefined): string {
      if (projectId === undefined || projectId === null) {
        return join(dataDir, "knowledge");
      }
      const project = getDatabase()
        .prepare("SELECT path FROM projects WHERE id = ?")
        .get(projectId) as { path: string | null } | undefined;
      if (!project?.path) {
        throw new Error(`Project not found: ${projectId}`);
      }
      return project.path;
    }
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description fully discloses behavioral traits: idempotency, nesting creation, rejection criteria, side effect of disk mkdir without DB rows until a file is added, and return structure {path, base_path}. No contradictions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Every sentence provides essential information: core action, idempotency, nesting, rejection conditions, side effects, return. No wasted words. Front-loaded with purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given tool simplicity (2 params, no output schema), description covers all aspects: behavior, constraints, return value, side effects. No gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Input schema has 100% coverage with descriptions. Description adds value by explaining global constraints (e.g., rejections) and side effects that affect parameter interpretation. Exceeds the baseline of 3.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states verb (create), resource (folder), and scope (under project root or KB). It distinguishes from sibling tools like create_file and delete_folder by specifying folder creation and mentioning idempotency and nested paths.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Description explicitly states when the call fails (rejection conditions) and provides side-effect context. While it doesn't explicitly list alternatives, the sibling tools are distinct enough that usage is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/safiyu/ctxnest'

If you have feedback or need assistance with the MCP directory API, please join our Discord server