diff --git a/examples/agent/wiki.ts b/examples/agent/wiki.ts
index 70d1cc1d9cab1489767edb46efec5796ae4bc486..74504268684c31fe8da7cc792988d262b2951ccb 100644
--- a/examples/agent/wiki.ts
+++ b/examples/agent/wiki.ts
@@ -1,13 +1,12 @@
 import { OpenAI } from "@llamaindex/openai";
+import { wiki } from "@llamaindex/tools";
 import { AgentStream, agent } from "llamaindex";
-import { WikipediaTool } from "../wiki";
 
 async function main() {
   const llm = new OpenAI({ model: "gpt-4-turbo" });
-  const wikiTool = new WikipediaTool();
 
   const workflow = agent({
-    tools: [wikiTool],
+    tools: [wiki],
     llm,
     verbose: false,
   });
diff --git a/examples/agentworkflow/blog-writer.ts b/examples/agentworkflow/blog-writer.ts
index d72cfd778a9c395944f496733007d4d290ec8a31..f7a0bd4116c83f93408ef9f94e6d34a9f808e40c 100644
--- a/examples/agentworkflow/blog-writer.ts
+++ b/examples/agentworkflow/blog-writer.ts
@@ -10,7 +10,7 @@ import {
 import os from "os";
 import { z } from "zod";
 
-import { WikipediaTool } from "../wiki";
+import { wiki } from "@llamaindex/tools";
 const llm = openai({
   model: "gpt-4o-mini",
 });
@@ -46,7 +46,7 @@ async function main() {
     description:
       "Responsible for gathering relevant information from the internet",
     systemPrompt: `You are a research agent. Your role is to gather information from the internet using the provided tools and then transfer this information to the report agent for content creation.`,
-    tools: [new WikipediaTool()],
+    tools: [wiki],
     canHandoffTo: [reportAgent],
     llm,
   });
diff --git a/examples/anthropic/agent.ts b/examples/anthropic/agent.ts
index 8f0cf2205c231c71ad35385a83f33ae93eed9ada..6aaac73fbd315cf15fedb70d05675a629d4794a9 100644
--- a/examples/anthropic/agent.ts
+++ b/examples/anthropic/agent.ts
@@ -1,7 +1,7 @@
 import { anthropic } from "@llamaindex/anthropic";
+import { wiki } from "@llamaindex/tools";
 import { agent, tool } from "llamaindex";
 import { z } from "zod";
-import { WikipediaTool } from "../wiki";
 
 const workflow = agent({
   tools: [
@@ -13,7 +13,7 @@ const workflow = agent({
       }),
       execute: ({ location }) => `The weather in ${location} is sunny`,
     }),
-    new WikipediaTool(),
+    wiki,
   ],
   llm: anthropic({
     apiKey: process.env.ANTHROPIC_API_KEY,
diff --git a/examples/package.json b/examples/package.json
index 912a7bf14ccedb13f433d463573927ee6ccea128..4b8eace580fafa3c80f1650407a1ce2238814065 100644
--- a/examples/package.json
+++ b/examples/package.json
@@ -49,6 +49,7 @@
     "@llamaindex/together": "^0.0.5",
     "@llamaindex/jinaai": "^0.0.5",
     "@llamaindex/perplexity": "^0.0.2",
+    "@llamaindex/tools": "^0.0.1",
     "@notionhq/client": "^2.2.15",
     "@pinecone-database/pinecone": "^4.0.0",
     "@vercel/postgres": "^0.10.0",
diff --git a/examples/vercel/llm.ts b/examples/vercel/llm.ts
index 302a53358bee752dcbd92fff6344353a0a298982..15fb4a1987a7425352ea694aae898fd8407a2494 100644
--- a/examples/vercel/llm.ts
+++ b/examples/vercel/llm.ts
@@ -1,7 +1,7 @@
 import { openai } from "@ai-sdk/openai";
+import { wiki } from "@llamaindex/tools";
 import { VercelLLM } from "@llamaindex/vercel";
 import { LLMAgent } from "llamaindex";
-import { WikipediaTool } from "../wiki";
 
 async function main() {
   // Create an instance of VercelLLM with the OpenAI model
@@ -33,7 +33,7 @@ async function main() {
   console.log("\n=== Test 3: Using LLMAgent with WikipediaTool ===");
   const agent = new LLMAgent({
     llm: vercelLLM,
-    tools: [new WikipediaTool()],
+    tools: [wiki],
   });
 
   const { message } = await agent.chat({
diff --git a/packages/cloud/package.json b/packages/cloud/package.json
index b70cd421a9e0357549f70dabf242bdbc1f013712..00f4fd77f4c72cd69737fa9664582e08acf6bc92 100644
--- a/packages/cloud/package.json
+++ b/packages/cloud/package.json
@@ -4,7 +4,7 @@
   "type": "module",
   "license": "MIT",
   "scripts": {
-    "generate": "./node_modules/.bin/openapi-ts",
+    "generate": "openapi-ts",
     "build": "pnpm run generate && bunchee",
     "dev": "bunchee --watch"
   },
diff --git a/packages/server/package.json b/packages/server/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..02d6627a72bb700d1308334e7114a1fe415fe092
--- /dev/null
+++ b/packages/server/package.json
@@ -0,0 +1,42 @@
+{
+  "name": "@llamaindex/server",
+  "description": "LlamaIndex Server",
+  "version": "0.0.1",
+  "type": "module",
+  "main": "./dist/index.cjs",
+  "module": "./dist/index.js",
+  "exports": {
+    ".": {
+      "require": {
+        "types": "./dist/index.d.cts",
+        "default": "./dist/index.cjs"
+      },
+      "import": {
+        "types": "./dist/index.d.ts",
+        "default": "./dist/index.js"
+      }
+    }
+  },
+  "files": [
+    "dist"
+  ],
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/run-llama/LlamaIndexTS.git",
+    "directory": "packages/server"
+  },
+  "scripts": {
+    "build": "bunchee",
+    "dev": "bunchee --watch",
+    "test": "vitest run"
+  },
+  "devDependencies": {
+    "bunchee": "6.4.0",
+    "vitest": "^2.1.5",
+    "@types/node": "^22.9.0"
+  },
+  "dependencies": {
+    "@llamaindex/core": "workspace:*",
+    "@llamaindex/env": "workspace:*"
+  }
+}
diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4c747052839bc2808f3aa25f41447a2ee4be16e3
--- /dev/null
+++ b/packages/server/src/index.ts
@@ -0,0 +1 @@
+export { LlamaIndexServer } from "./server.js";
diff --git a/packages/server/src/server.ts b/packages/server/src/server.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8919974de76260ce2d2048245c6c3ac45d64bae5
--- /dev/null
+++ b/packages/server/src/server.ts
@@ -0,0 +1,22 @@
+import express, { Express } from "express";
+
+export interface LlamaIndexServerConfig {
+  modules?: LlamaIndexServerModule[];
+  storage?: StorageService;
+}
+
+/**
+ * Goal:
+ * - user can get the whole server instance to run (express server)
+ * - user can get controllers and add to their current router
+ * - provide adapter to route handlers in Nextjs able to use it also
+ * - by default, we provide chat module, user can config addOn to use LlamaCloud, Sandbox, etc.
+ * - by default, we use filesystem storage, user can config to use other storage
+ */
+export class LlamaIndexServer {
+  app: Express;
+
+  constructor() {
+    this.app = express();
+  }
+}
diff --git a/packages/server/tsconfig.json b/packages/server/tsconfig.json
new file mode 100644
index 0000000000000000000000000000000000000000..a93775d954ab510bbae6d3aaabe2c7204f557e2b
--- /dev/null
+++ b/packages/server/tsconfig.json
@@ -0,0 +1,15 @@
+{
+  "extends": "../../tsconfig.json",
+  "compilerOptions": {
+    "rootDir": "./src",
+    "outDir": "./dist/type",
+    "tsBuildInfoFile": "./dist/.tsbuildinfo",
+    "emitDeclarationOnly": true,
+    "moduleResolution": "Bundler",
+    "skipLibCheck": true,
+    "strict": true,
+    "types": ["node"]
+  },
+  "include": ["./src"],
+  "exclude": ["node_modules"]
+}
diff --git a/packages/tools/package.json b/packages/tools/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..0e0be05cfc2a34961120e92ea8cbbd07c85525b4
--- /dev/null
+++ b/packages/tools/package.json
@@ -0,0 +1,46 @@
+{
+  "name": "@llamaindex/tools",
+  "description": "LlamaIndex Tools",
+  "version": "0.0.1",
+  "type": "module",
+  "main": "./dist/index.cjs",
+  "module": "./dist/index.js",
+  "exports": {
+    ".": {
+      "require": {
+        "types": "./dist/index.d.cts",
+        "default": "./dist/index.cjs"
+      },
+      "import": {
+        "types": "./dist/index.d.ts",
+        "default": "./dist/index.js"
+      }
+    }
+  },
+  "files": [
+    "dist"
+  ],
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/run-llama/LlamaIndexTS.git",
+    "directory": "packages/tools"
+  },
+  "scripts": {
+    "build": "bunchee",
+    "dev": "bunchee --watch",
+    "test": "vitest run"
+  },
+  "devDependencies": {
+    "bunchee": "6.4.0",
+    "vitest": "^2.1.5",
+    "@types/node": "^22.9.0"
+  },
+  "dependencies": {
+    "@llamaindex/core": "workspace:*",
+    "@llamaindex/env": "workspace:*",
+    "@e2b/code-interpreter": "^1.0.4",
+    "ajv": "^8.12.0",
+    "wikipedia": "^2.1.2",
+    "zod": "^3.23.8"
+  }
+}
diff --git a/packages/tools/src/index.ts b/packages/tools/src/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..61e6a65cbae1481aa330f4145da37396332b0e93
--- /dev/null
+++ b/packages/tools/src/index.ts
@@ -0,0 +1,9 @@
+export * from "./tools/document-generator";
+export * from "./tools/interpreter";
+export * from "./tools/weather";
+export * from "./tools/wiki";
+
+// Export configuration system
+export * from "./config";
+
+// TODO: export other tools
diff --git a/packages/tools/src/settings.ts b/packages/tools/src/settings.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d0d0080d457b23ea4c4e7e49a769fb31b47cefb9
--- /dev/null
+++ b/packages/tools/src/settings.ts
@@ -0,0 +1,22 @@
+class GlobalToolSettings {
+  private _outputDir: string = "output/tools";
+  private _fileServerURLPrefix: string | undefined;
+
+  set outputDir(outputDir: string) {
+    this._outputDir = outputDir;
+  }
+
+  get outputDir() {
+    return this._outputDir;
+  }
+
+  set fileServerURLPrefix(fileServerURLPrefix: string | undefined) {
+    this._fileServerURLPrefix = fileServerURLPrefix;
+  }
+
+  get fileServerURLPrefix() {
+    return this._fileServerURLPrefix;
+  }
+}
+
+export const ToolSettings = new GlobalToolSettings();
diff --git a/packages/tools/src/tools/interpreter.ts b/packages/tools/src/tools/interpreter.ts
new file mode 100644
index 0000000000000000000000000000000000000000..bcc4019cb1a9bcce2fa64e2b7946c45314921926
--- /dev/null
+++ b/packages/tools/src/tools/interpreter.ts
@@ -0,0 +1,249 @@
+import { type Logs, Result, Sandbox } from "@e2b/code-interpreter";
+import { type BaseTool, type ToolMetadata } from "@llamaindex/core/llms";
+import type { JSONSchemaType } from "ajv";
+import fs from "fs";
+import crypto from "node:crypto";
+import path from "node:path";
+
+export type InterpreterParameter = {
+  code: string;
+  sandboxFiles?: string[];
+  retryCount?: number;
+};
+
+export type InterpreterToolParams = {
+  metadata?: ToolMetadata<JSONSchemaType<InterpreterParameter>>;
+  apiKey?: string;
+  fileServerURLPrefix?: string;
+};
+
+export type InterpreterToolOutput = {
+  isError: boolean;
+  logs: Logs;
+  text?: string | undefined;
+  extraResult: InterpreterExtraResult[];
+  retryCount?: number | undefined;
+};
+
+type InterpreterExtraType =
+  | "html"
+  | "markdown"
+  | "svg"
+  | "png"
+  | "jpeg"
+  | "pdf"
+  | "latex"
+  | "json"
+  | "javascript";
+
+export type InterpreterExtraResult = {
+  type: InterpreterExtraType;
+  content?: string;
+  filename?: string;
+  url?: string;
+};
+
+const DEFAULT_META_DATA: ToolMetadata<JSONSchemaType<InterpreterParameter>> = {
+  name: "interpreter",
+  description: `Execute python code in a Jupyter notebook cell and return any result, stdout, stderr, display_data, and error.
+If the code needs to use a file, ALWAYS pass the file path in the sandbox_files argument.
+You have a maximum of 3 retries to get the code to run successfully.
+`,
+  parameters: {
+    type: "object",
+    properties: {
+      code: {
+        type: "string",
+        description: "The python code to execute in a single cell.",
+      },
+      sandboxFiles: {
+        type: "array",
+        description:
+          "List of local file paths to be used by the code. The tool will throw an error if a file is not found.",
+        items: {
+          type: "string",
+        },
+        nullable: true,
+      },
+      retryCount: {
+        type: "number",
+        description: "The number of times the tool has been retried",
+        default: 0,
+        nullable: true,
+      },
+    },
+    required: ["code"],
+  },
+};
+
+export class InterpreterTool implements BaseTool<InterpreterParameter> {
+  private readonly outputDir = "output/tools";
+  private readonly uploadedFilesDir = "output/uploaded";
+  private apiKey: string;
+  private fileServerURLPrefix: string;
+  metadata: ToolMetadata<JSONSchemaType<InterpreterParameter>>;
+  codeInterpreter?: Sandbox;
+
+  constructor(params?: InterpreterToolParams) {
+    this.metadata = params?.metadata || DEFAULT_META_DATA;
+    this.apiKey = params?.apiKey || process.env.E2B_API_KEY!;
+    this.fileServerURLPrefix =
+      params?.fileServerURLPrefix || process.env.FILESERVER_URL_PREFIX!;
+
+    if (!this.apiKey) {
+      throw new Error(
+        "E2B_API_KEY key is required to run code interpreter. Get it here: https://e2b.dev/docs/getting-started/api-key",
+      );
+    }
+    if (!this.fileServerURLPrefix) {
+      throw new Error(
+        "FILESERVER_URL_PREFIX is required to display file output from sandbox",
+      );
+    }
+  }
+
+  public async initInterpreter(input: InterpreterParameter) {
+    if (!this.codeInterpreter) {
+      this.codeInterpreter = await Sandbox.create({
+        apiKey: this.apiKey,
+      });
+      // upload files to sandbox when it's initialized
+      if (input.sandboxFiles) {
+        console.log(`Uploading ${input.sandboxFiles.length} files to sandbox`);
+        try {
+          for (const filePath of input.sandboxFiles) {
+            const fileName = path.basename(filePath);
+            const localFilePath = path.join(this.uploadedFilesDir, fileName);
+            const content = fs.readFileSync(localFilePath);
+
+            const arrayBuffer = new Uint8Array(content).buffer;
+            await this.codeInterpreter?.files.write(filePath, arrayBuffer);
+          }
+        } catch (error) {
+          console.error("Got error when uploading files to sandbox", error);
+        }
+      }
+    }
+
+    return this.codeInterpreter;
+  }
+
+  public async codeInterpret(
+    input: InterpreterParameter,
+  ): Promise<InterpreterToolOutput> {
+    console.log(
+      `Sandbox files: ${input.sandboxFiles}. Retry count: ${input.retryCount}`,
+    );
+
+    if (input.retryCount && input.retryCount >= 3) {
+      return {
+        isError: true,
+        logs: {
+          stdout: [],
+          stderr: [],
+        },
+        text: "Max retries reached",
+        extraResult: [],
+      };
+    }
+
+    console.log(
+      `\n${"=".repeat(50)}\n> Running following AI-generated code:\n${input.code}\n${"=".repeat(50)}`,
+    );
+    const interpreter = await this.initInterpreter(input);
+    const exec = await interpreter.runCode(input.code);
+    if (exec.error) console.error("[Code Interpreter error]", exec.error);
+    const extraResult = await this.getExtraResult(exec.results[0]);
+    const result: InterpreterToolOutput = {
+      isError: !!exec.error,
+      logs: exec.logs,
+      text: exec.text,
+      extraResult,
+      retryCount: input.retryCount ? input.retryCount + 1 : 1,
+    };
+    return result;
+  }
+
+  async call(input: InterpreterParameter): Promise<InterpreterToolOutput> {
+    const result = await this.codeInterpret(input);
+    return result;
+  }
+
+  async close() {
+    await this.codeInterpreter?.kill();
+  }
+
+  private async getExtraResult(
+    res?: Result,
+  ): Promise<InterpreterExtraResult[]> {
+    if (!res) return [];
+    const output: InterpreterExtraResult[] = [];
+
+    try {
+      const formats = res.formats(); // formats available for the result. Eg: ['png', ...]
+      const results = formats.map((f) => res[f as keyof Result]); // get base64 data for each format
+
+      // save base64 data to file and return the url
+      for (let i = 0; i < formats.length; i++) {
+        const ext = formats[i];
+        const data = results[i];
+        switch (ext) {
+          case "png":
+          case "jpeg":
+          case "svg":
+          case "pdf": {
+            const { filename } = this.saveToDisk(data, ext);
+            output.push({
+              type: ext as InterpreterExtraType,
+              filename,
+              url: this.getFileUrl(filename),
+            });
+            break;
+          }
+          default:
+            output.push({
+              type: ext as InterpreterExtraType,
+              content: data,
+            });
+            break;
+        }
+      }
+    } catch (error) {
+      console.error("Error when parsing e2b response", error);
+    }
+
+    return output;
+  }
+
+  // Consider saving to cloud storage instead but it may cost more for you
+  // See: https://e2b.dev/docs/sandbox/api/filesystem#write-to-file
+  private saveToDisk(
+    base64Data: string,
+    ext: string,
+  ): {
+    outputPath: string;
+    filename: string;
+  } {
+    const filename = `${crypto.randomUUID()}.${ext}`; // generate a unique filename
+    const buffer = Buffer.from(base64Data, "base64");
+    const outputPath = this.getOutputPath(filename);
+    fs.writeFileSync(outputPath, buffer);
+    console.log(`Saved file to ${outputPath}`);
+    return {
+      outputPath,
+      filename,
+    };
+  }
+
+  private getOutputPath(filename: string): string {
+    // if outputDir doesn't exist, create it
+    if (!fs.existsSync(this.outputDir)) {
+      fs.mkdirSync(this.outputDir, { recursive: true });
+    }
+    return path.join(this.outputDir, filename);
+  }
+
+  private getFileUrl(filename: string): string {
+    return `${this.fileServerURLPrefix}/${this.outputDir}/${filename}`;
+  }
+}
diff --git a/packages/tools/src/tools/weather.ts b/packages/tools/src/tools/weather.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6f3206b127d3d84455d7ec25a95cb9f0d76823a0
--- /dev/null
+++ b/packages/tools/src/tools/weather.ts
@@ -0,0 +1,92 @@
+import { tool } from "@llamaindex/core/tools";
+import { z } from "zod";
+
+export type WeatherToolOutput = {
+  latitude: number;
+  longitude: number;
+  generationtime_ms: number;
+  utc_offset_seconds: number;
+  timezone: string;
+  timezone_abbreviation: string;
+  elevation: number;
+  current_units: {
+    time: string;
+    interval: string;
+    temperature_2m: string;
+    weather_code: string;
+  };
+  current: {
+    time: string;
+    interval: number;
+    temperature_2m: number;
+    weather_code: number;
+  };
+  hourly_units: {
+    time: string;
+    temperature_2m: string;
+    weather_code: string;
+  };
+  hourly: {
+    time: string[];
+    temperature_2m: number[];
+    weather_code: number[];
+  };
+  daily_units: {
+    time: string;
+    weather_code: string;
+  };
+  daily: {
+    time: string[];
+    weather_code: number[];
+  };
+};
+
+export const weather = tool({
+  name: "weather",
+  description: `
+    Use this function to get the weather of any given location.
+    Note that the weather code should follow WMO Weather interpretation codes (WW):
+    0: Clear sky
+    1, 2, 3: Mainly clear, partly cloudy, and overcast
+    45, 48: Fog and depositing rime fog
+    51, 53, 55: Drizzle: Light, moderate, and dense intensity
+    56, 57: Freezing Drizzle: Light and dense intensity
+    61, 63, 65: Rain: Slight, moderate and heavy intensity
+    66, 67: Freezing Rain: Light and heavy intensity
+    71, 73, 75: Snow fall: Slight, moderate, and heavy intensity
+    77: Snow grains
+    80, 81, 82: Rain showers: Slight, moderate, and violent
+    85, 86: Snow showers slight and heavy
+    95: Thunderstorm: Slight or moderate
+    96, 99: Thunderstorm with slight and heavy hail
+  `,
+  parameters: z.object({
+    location: z.string().describe("The location to get the weather"),
+  }),
+  execute: async ({
+    location,
+  }: {
+    location: string;
+  }): Promise<WeatherToolOutput> => {
+    return await getWeatherByLocation(location);
+  },
+});
+
+async function getWeatherByLocation(location: string) {
+  const { latitude, longitude } = await getGeoLocation(location);
+  const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
+  const apiUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&current=temperature_2m,weather_code&hourly=temperature_2m,weather_code&daily=weather_code&timezone=${timezone}`;
+  const response = await fetch(apiUrl);
+  const data = (await response.json()) as WeatherToolOutput;
+  return data;
+}
+
+async function getGeoLocation(
+  location: string,
+): Promise<{ latitude: number; longitude: number }> {
+  const apiUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${location}&count=10&language=en&format=json`;
+  const response = await fetch(apiUrl);
+  const data = await response.json();
+  const { latitude, longitude } = data.results[0];
+  return { latitude, longitude };
+}
diff --git a/packages/tools/src/tools/wiki.ts b/packages/tools/src/tools/wiki.ts
new file mode 100644
index 0000000000000000000000000000000000000000..741ec452ef4ecfcf388d79cca6214ad415a39eb0
--- /dev/null
+++ b/packages/tools/src/tools/wiki.ts
@@ -0,0 +1,25 @@
+import { tool } from "@llamaindex/core/tools";
+import { default as wikipedia } from "wikipedia";
+import { z } from "zod";
+
+export type WikiToolOutput = {
+  title: string;
+  content: string;
+};
+
+export const wiki = tool({
+  name: "wikipedia",
+  description: "Use this function to search Wikipedia",
+  parameters: z.object({
+    query: z.string().describe("The query to search for"),
+    lang: z.string().describe("The language to search in").default("en"),
+  }),
+  execute: async ({ query, lang }): Promise<WikiToolOutput> => {
+    wikipedia.setLang(lang);
+    const searchResult = await wikipedia.search(query);
+    const pageTitle = searchResult.results[0].title;
+    if (!pageTitle) return { title: "No search results.", content: "" };
+    const pageResult = await wikipedia.page(pageTitle, { autoSuggest: false });
+    return { title: pageTitle, content: await pageResult.content() };
+  },
+});
diff --git a/packages/tools/tsconfig.json b/packages/tools/tsconfig.json
new file mode 100644
index 0000000000000000000000000000000000000000..a93775d954ab510bbae6d3aaabe2c7204f557e2b
--- /dev/null
+++ b/packages/tools/tsconfig.json
@@ -0,0 +1,15 @@
+{
+  "extends": "../../tsconfig.json",
+  "compilerOptions": {
+    "rootDir": "./src",
+    "outDir": "./dist/type",
+    "tsBuildInfoFile": "./dist/.tsbuildinfo",
+    "emitDeclarationOnly": true,
+    "moduleResolution": "Bundler",
+    "skipLibCheck": true,
+    "strict": true,
+    "types": ["node"]
+  },
+  "include": ["./src"],
+  "exclude": ["node_modules"]
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 2b1aab4a8096cd902b90a6a57a9c0dd5d3798807..4c61deeb85ff7ee22dab2534f943c8ed1a8e73fa 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -680,6 +680,9 @@ importers:
       '@llamaindex/together':
         specifier: ^0.0.5
         version: link:../packages/providers/together
+      '@llamaindex/tools':
+        specifier: ^0.0.1
+        version: link:../packages/tools
       '@llamaindex/upstash':
         specifier: ^0.0.13
         version: link:../packages/providers/storage/upstash
@@ -1709,6 +1712,56 @@ importers:
         specifier: ^13.4.8
         version: 13.4.8
 
+  packages/server:
+    dependencies:
+      '@llamaindex/core':
+        specifier: workspace:*
+        version: link:../core
+      '@llamaindex/env':
+        specifier: workspace:*
+        version: link:../env
+    devDependencies:
+      '@types/node':
+        specifier: ^22.9.0
+        version: 22.9.0
+      bunchee:
+        specifier: 6.4.0
+        version: 6.4.0(typescript@5.7.3)
+      vitest:
+        specifier: ^2.1.5
+        version: 2.1.5(@edge-runtime/vm@4.0.4)(@types/node@22.9.0)(happy-dom@15.11.7)(lightningcss@1.29.1)(msw@2.7.0(@types/node@22.9.0)(typescript@5.7.3))(terser@5.38.2)
+
+  packages/tools:
+    dependencies:
+      '@e2b/code-interpreter':
+        specifier: ^1.0.4
+        version: 1.0.4
+      '@llamaindex/core':
+        specifier: workspace:*
+        version: link:../core
+      '@llamaindex/env':
+        specifier: workspace:*
+        version: link:../env
+      ajv:
+        specifier: ^8.12.0
+        version: 8.17.1
+      wikipedia:
+        specifier: ^2.1.2
+        version: 2.1.2
+      zod:
+        specifier: ^3.23.8
+        version: 3.24.2
+    devDependencies:
+      '@types/node':
+        specifier: ^22.9.0
+        version: 22.9.0
+      bunchee:
+        specifier: 6.4.0
+        version: 6.4.0(typescript@5.7.3)
+      vitest:
+        specifier: ^2.1.5
+        version: 2.1.5(@edge-runtime/vm@4.0.4)(@types/node@22.9.0)(happy-dom@15.11.7)(lightningcss@1.29.1)(msw@2.7.0(@types/node@22.9.0)(typescript@5.7.3))(terser@5.38.2)
+
   packages/wasm-tools:
     dependencies:
       '@assemblyscript/loader':
@@ -2234,6 +2287,9 @@ packages:
     resolution: {integrity: sha512-eUuWapzEGWFEpHFxgEaBG8e3n6S8L3MSu0oda755rOfabWPnh0Our1AozNFVUxGFIhbKgd1ksprsoDGMinTOTA==}
     engines: {node: '>=6.9.0'}
 
+  '@bufbuild/protobuf@2.2.3':
+    resolution: {integrity: sha512-tFQoXHJdkEOSwj5tRIZSPNUuXK3RaR7T1nUrPgbYX1pUbvqqaaZAsfo+NXBPsz5rZMSKVFrgK1WL8Q/MSLvprg==}
+
   '@bundled-es-modules/cookie@2.0.1':
     resolution: {integrity: sha512-8o+5fRPLNbjbdGRRmJj3h6Hh1AQJf2dk3qQ/5ZFb+PXkRNiSoMGGUKlsgLfrxneb72axVJyIYji64E2+nNfYyw==}
 
@@ -2415,6 +2471,17 @@ packages:
     resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==}
     engines: {node: '>=0.1.90'}
 
+  '@connectrpc/connect-web@2.0.0-rc.3':
+    resolution: {integrity: sha512-w88P8Lsn5CCsA7MFRl2e6oLY4J/5toiNtJns/YJrlyQaWOy3RO8pDgkz+iIkG98RPMhj2thuBvsd3Cn4DKKCkw==}
+    peerDependencies:
+      '@bufbuild/protobuf': ^2.2.0
+      '@connectrpc/connect': 2.0.0-rc.3
+
+  '@connectrpc/connect@2.0.0-rc.3':
+    resolution: {integrity: sha512-ARBt64yEyKbanyRETTjcjJuHr2YXorzQo0etyS5+P6oSeW8xEuzajA9g+zDnMcj1hlX2dQE93foIWQGfpru7gQ==}
+    peerDependencies:
+      '@bufbuild/protobuf': ^2.2.0
+
   '@cspotcode/source-map-support@0.8.1':
     resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
     engines: {node: '>=12'}
@@ -2446,6 +2513,10 @@ packages:
     resolution: {integrity: sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ==}
     engines: {node: '>=14.17.0'}
 
+  '@e2b/code-interpreter@1.0.4':
+    resolution: {integrity: sha512-8y82UMXBdf/hye8bX2Fn04JlL72rvOenVgsvMZ+cAJqo6Ijdl4EmzzuFpM4mz9s+EJ29+34lGHBp277tiLWuiA==}
+    engines: {node: '>=18'}
+
   '@edge-runtime/primitives@5.1.1':
     resolution: {integrity: sha512-osrHE4ObQ3XFkvd1sGBLkheV2mcHUqJI/Bum2AWA0R3U78h9lif3xZAdl6eLD/XnW4xhsdwjPUejLusXbjvI4Q==}
     engines: {node: '>=16'}
@@ -6514,6 +6585,9 @@ packages:
   commondir@1.0.1:
     resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==}
 
+  compare-versions@6.1.1:
+    resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==}
+
   compute-scroll-into-view@3.1.1:
     resolution: {integrity: sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==}
 
@@ -6847,6 +6921,10 @@ packages:
   duplexify@4.1.3:
     resolution: {integrity: sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==}
 
+  e2b@1.0.7:
+    resolution: {integrity: sha512-7msagBbQ8tm51qaGp+hdaaaMjGG3zCzZtUS8bnz+LK7wdwtVTA1PmX+1Br9E3R7v6XIchnNWRpei+VjvGcfidA==}
+    engines: {node: '>=18'}
+
   eastasianwidth@0.2.0:
     resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
 
@@ -9602,9 +9680,15 @@ packages:
       zod:
         optional: true
 
+  openapi-fetch@0.9.8:
+    resolution: {integrity: sha512-zM6elH0EZStD/gSiNlcPrzXcVQ/pZo3BDvC6CDwRDUt1dDzxlshpmQnpD6cZaJ39THaSmwVCxxRrPKNM1hHrDg==}
+
   openapi-sampler@1.6.1:
     resolution: {integrity: sha512-s1cIatOqrrhSj2tmJ4abFYZQK6l5v+V4toO5q1Pa0DyN8mtyqy2I+Qrj5W9vOELEtybIMQs/TBZGVO/DtTFK8w==}
 
+  openapi-typescript-helpers@0.0.8:
+    resolution: {integrity: sha512-1eNjQtbfNi5Z/kFhagDIaIRj6qqDzhjNJKz8cmMW0CVdGwT6e1GLbAfgI0d28VTJa1A8jz82jm/4dG8qNoNS8g==}
+
   opener@1.5.2:
     resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==}
     hasBin: true
@@ -13031,6 +13115,8 @@ snapshots:
       '@babel/helper-string-parser': 7.25.9
       '@babel/helper-validator-identifier': 7.25.9
 
+  '@bufbuild/protobuf@2.2.3': {}
+
   '@bundled-es-modules/cookie@2.0.1':
     dependencies:
       cookie: 0.7.2
@@ -13342,6 +13428,15 @@ snapshots:
 
   '@colors/colors@1.6.0': {}
 
+  '@connectrpc/connect-web@2.0.0-rc.3(@bufbuild/protobuf@2.2.3)(@connectrpc/connect@2.0.0-rc.3(@bufbuild/protobuf@2.2.3))':
+    dependencies:
+      '@bufbuild/protobuf': 2.2.3
+      '@connectrpc/connect': 2.0.0-rc.3(@bufbuild/protobuf@2.2.3)
+
+  '@connectrpc/connect@2.0.0-rc.3(@bufbuild/protobuf@2.2.3)':
+    dependencies:
+      '@bufbuild/protobuf': 2.2.3
+
   '@cspotcode/source-map-support@0.8.1':
     dependencies:
       '@jridgewell/trace-mapping': 0.3.9
@@ -13382,6 +13477,10 @@ snapshots:
 
   '@discoveryjs/json-ext@0.6.3': {}
 
+  '@e2b/code-interpreter@1.0.4':
+    dependencies:
+      e2b: 1.0.7
+
   '@edge-runtime/primitives@5.1.1': {}
 
   '@edge-runtime/vm@4.0.4':
@@ -17740,6 +17839,8 @@ snapshots:
 
   commondir@1.0.1: {}
 
+  compare-versions@6.1.1: {}
+
   compute-scroll-into-view@3.1.1: {}
 
   concat-map@0.0.1: {}
@@ -18045,6 +18146,15 @@ snapshots:
       readable-stream: 3.6.2
       stream-shift: 1.0.3
 
+  e2b@1.0.7:
+    dependencies:
+      '@bufbuild/protobuf': 2.2.3
+      '@connectrpc/connect': 2.0.0-rc.3(@bufbuild/protobuf@2.2.3)
+      '@connectrpc/connect-web': 2.0.0-rc.3(@bufbuild/protobuf@2.2.3)(@connectrpc/connect@2.0.0-rc.3(@bufbuild/protobuf@2.2.3))
+      compare-versions: 6.1.1
+      openapi-fetch: 0.9.8
+      platform: 1.3.6
+
   eastasianwidth@0.2.0: {}
 
   ecdsa-sig-formatter@1.0.11:
@@ -22042,12 +22152,18 @@ snapshots:
     transitivePeerDependencies:
       - encoding
 
+  openapi-fetch@0.9.8:
+    dependencies:
+      openapi-typescript-helpers: 0.0.8
+
   openapi-sampler@1.6.1:
     dependencies:
       '@types/json-schema': 7.0.15
       fast-xml-parser: 4.5.3
       json-pointer: 0.6.2
 
+  openapi-typescript-helpers@0.0.8: {}
+
   opener@1.5.2: {}
 
   option@0.2.4: {}
diff --git a/tsconfig.json b/tsconfig.json
index 0dbe6a06115202cb5baf0b8c4459df920092d628..f15054ed52f62ffeebb0dcf6d7bf133687d5b8c7 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -190,6 +190,12 @@
     },
     {
       "path": "./packages/providers/perplexity/tsconfig.json"
+    },
+    {
+      "path": "./packages/server/tsconfig.json"
+    },
+    {
+      "path": "./packages/tools/tsconfig.json"
     }
   ]
 }