@chapterai/mcp 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +251 -0
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -22439,6 +22439,29 @@ var api = {
22439
22439
  return getClient().workspaces.getWorkspaceStats.query(input);
22440
22440
  }
22441
22441
  },
22442
+ intelligence: {
22443
+ scan(input) {
22444
+ return getClient().intelligence.scan.mutate(input);
22445
+ },
22446
+ query(input) {
22447
+ return getClient().intelligence.query.query(input);
22448
+ },
22449
+ findSymbol(input) {
22450
+ return getClient().intelligence.findSymbol.query(input);
22451
+ },
22452
+ findCopy(input) {
22453
+ return getClient().intelligence.findCopy.query(input);
22454
+ },
22455
+ contextForTask(input) {
22456
+ return getClient().intelligence.contextForTask.query(input);
22457
+ },
22458
+ fileMap(input) {
22459
+ return getClient().intelligence.fileMap.query(input);
22460
+ },
22461
+ deps(input) {
22462
+ return getClient().intelligence.deps.query(input);
22463
+ }
22464
+ },
22442
22465
  sessions: {
22443
22466
  list(input) {
22444
22467
  return getClient().sessions.list.query(input);
@@ -23539,6 +23562,233 @@ ${lines.join("\n")}`);
23539
23562
  );
23540
23563
  }
23541
23564
 
23565
+ // src/tools/intelligence.ts
23566
+ function registerIntelligenceTools(server2) {
23567
+ server2.tool(
23568
+ "scan_codebase",
23569
+ "Scan and index a codebase to build a structured map of all files, symbols, routes, endpoints, models, and copy. Run this once per workspace to enable fast lookups. Accepts an optional projectPath for local directories.",
23570
+ {
23571
+ workspaceId: external_exports.string().uuid().optional().describe("Workspace ID"),
23572
+ workspaceName: external_exports.string().optional().describe("Workspace name (alternative to ID)"),
23573
+ projectPath: external_exports.string().optional().describe("Local filesystem path to scan (overrides workspace path)")
23574
+ },
23575
+ async ({ workspaceId, workspaceName, projectPath }) => {
23576
+ try {
23577
+ const id = await resolveWorkspaceId(workspaceId, workspaceName);
23578
+ const result = await api.intelligence.scan({
23579
+ workspaceId: id,
23580
+ projectPath
23581
+ });
23582
+ const lines = [
23583
+ `Codebase scanned in ${result.stats.durationMs}ms`,
23584
+ ``,
23585
+ `Files: ${result.fileCount}`,
23586
+ `Symbols: ${result.symbolCount}`,
23587
+ `Routes: ${result.routeCount}`,
23588
+ `API endpoints: ${result.endpointCount}`,
23589
+ `DB models: ${result.modelCount}`,
23590
+ `Copy entries: ${result.copyCount}`,
23591
+ `Dependencies: ${result.dependencyCount}`,
23592
+ ``,
23593
+ `Tech stack:`,
23594
+ ` Languages: ${result.techStack.languages.join(", ")}`,
23595
+ ` Frameworks: ${result.techStack.frameworks.join(", ")}`,
23596
+ ` Databases: ${result.techStack.databases.join(", ")}`,
23597
+ ` Package manager: ${result.techStack.packageManager ?? "unknown"}`
23598
+ ];
23599
+ return success(lines.join("\n"));
23600
+ } catch (error2) {
23601
+ return formatError2(error2);
23602
+ }
23603
+ }
23604
+ );
23605
+ server2.tool(
23606
+ "query_codebase",
23607
+ "Search the codebase index for files, symbols, routes, endpoints, and copy matching a query. Returns ranked results with file paths and line numbers. The index must exist (run scan_codebase first).",
23608
+ {
23609
+ workspaceId: external_exports.string().uuid().optional().describe("Workspace ID"),
23610
+ workspaceName: external_exports.string().optional().describe("Workspace name (alternative to ID)"),
23611
+ query: external_exports.string().describe('Search query \u2014 e.g. "task creation", "auth middleware", "welcome page"'),
23612
+ limit: external_exports.number().optional().describe("Max results per category (default 20)")
23613
+ },
23614
+ async ({ workspaceId, workspaceName, query, limit }) => {
23615
+ try {
23616
+ const id = await resolveWorkspaceId(workspaceId, workspaceName);
23617
+ const result = await api.intelligence.query({ workspaceId: id, query, limit });
23618
+ const sections = [];
23619
+ if (result.files.length > 0) {
23620
+ sections.push("## Files");
23621
+ for (const f of result.files) {
23622
+ const exports = f.exports.length > 0 ? ` (exports: ${f.exports.slice(0, 3).join(", ")})` : "";
23623
+ sections.push(`- \`${f.path}\` [${f.category}]${exports}`);
23624
+ }
23625
+ }
23626
+ if (result.symbols.length > 0) {
23627
+ sections.push("\n## Symbols");
23628
+ for (const s of result.symbols) {
23629
+ const sig = s.signature ? ` \u2014 \`${s.signature}\`` : "";
23630
+ sections.push(`- \`${s.name}\` (${s.kind}) at \`${s.filePath}:${s.line}\`${sig}`);
23631
+ }
23632
+ }
23633
+ if (result.copy.length > 0) {
23634
+ sections.push("\n## Copy/Text");
23635
+ for (const c of result.copy) {
23636
+ sections.push(`- "${c.text}" at \`${c.filePath}:${c.line}\` in ${c.context}`);
23637
+ }
23638
+ }
23639
+ if (result.routes.length > 0) {
23640
+ sections.push("\n## Routes");
23641
+ for (const r of result.routes) {
23642
+ sections.push(`- ${r.method ?? "ANY"} \`${r.path}\` \u2192 ${r.handler} at \`${r.filePath}:${r.line}\``);
23643
+ }
23644
+ }
23645
+ if (result.endpoints.length > 0) {
23646
+ sections.push("\n## API Endpoints");
23647
+ for (const e of result.endpoints) {
23648
+ sections.push(`- \`${e.router ? e.router + "." : ""}${e.name}\` (${e.type}) at \`${e.filePath}:${e.line}\``);
23649
+ }
23650
+ }
23651
+ if (sections.length === 0) {
23652
+ return success(`No results found for "${query}". Try different keywords or run scan_codebase first.`);
23653
+ }
23654
+ return success(sections.join("\n"));
23655
+ } catch (error2) {
23656
+ return formatError2(error2);
23657
+ }
23658
+ }
23659
+ );
23660
+ server2.tool(
23661
+ "find_symbol",
23662
+ "Find a specific function, class, component, type, or other symbol by name. Returns exact file path and line number.",
23663
+ {
23664
+ workspaceId: external_exports.string().uuid().optional().describe("Workspace ID"),
23665
+ workspaceName: external_exports.string().optional().describe("Workspace name (alternative to ID)"),
23666
+ name: external_exports.string().describe('Symbol name to search for \u2014 e.g. "TaskCreateInline", "authorizeWorkspaceAccess"'),
23667
+ kind: external_exports.string().optional().describe("Filter by kind: function, class, component, type, interface, enum, hook, struct, method")
23668
+ },
23669
+ async ({ workspaceId, workspaceName, name, kind }) => {
23670
+ try {
23671
+ const id = await resolveWorkspaceId(workspaceId, workspaceName);
23672
+ const results = await api.intelligence.findSymbol({ workspaceId: id, name, kind });
23673
+ if (results.length === 0) {
23674
+ return success(`No symbol found matching "${name}"${kind ? ` (kind: ${kind})` : ""}`);
23675
+ }
23676
+ const lines = results.map((s) => {
23677
+ const sig = s.signature ? `
23678
+ ${s.signature}` : "";
23679
+ return `- \`${s.name}\` (${s.kind}) at \`${s.filePath}:${s.line}\`${s.exported ? " [exported]" : ""}${sig}`;
23680
+ });
23681
+ return success(`Found ${results.length} match(es):
23682
+ ${lines.join("\n")}`);
23683
+ } catch (error2) {
23684
+ return formatError2(error2);
23685
+ }
23686
+ }
23687
+ );
23688
+ server2.tool(
23689
+ "find_copy",
23690
+ "Find user-facing text/copy in the codebase by content. Returns the file path, line number, and surrounding component context. Use this to quickly locate where a specific string appears in the UI.",
23691
+ {
23692
+ workspaceId: external_exports.string().uuid().optional().describe("Workspace ID"),
23693
+ workspaceName: external_exports.string().optional().describe("Workspace name (alternative to ID)"),
23694
+ text: external_exports.string().describe('Text to search for \u2014 e.g. "Welcome to Chapter", "Sign in", "No tasks yet"')
23695
+ },
23696
+ async ({ workspaceId, workspaceName, text }) => {
23697
+ try {
23698
+ const id = await resolveWorkspaceId(workspaceId, workspaceName);
23699
+ const results = await api.intelligence.findCopy({ workspaceId: id, text });
23700
+ if (results.length === 0) {
23701
+ return success(`No copy found matching "${text}"`);
23702
+ }
23703
+ const lines = results.map(
23704
+ (c) => `- "${c.text}" at \`${c.filePath}:${c.line}\` in \`${c.context}\` (${c.type})`
23705
+ );
23706
+ return success(`Found ${results.length} match(es):
23707
+ ${lines.join("\n")}`);
23708
+ } catch (error2) {
23709
+ return formatError2(error2);
23710
+ }
23711
+ }
23712
+ );
23713
+ server2.tool(
23714
+ "get_codebase_context",
23715
+ "Generate a structured context block for a task description. Returns relevant files, symbols, copy, routes, and endpoints that an agent should know about before starting work. This is the key tool for speeding up agent sessions \u2014 call it at the start of any task.",
23716
+ {
23717
+ workspaceId: external_exports.string().uuid().optional().describe("Workspace ID"),
23718
+ workspaceName: external_exports.string().optional().describe("Workspace name (alternative to ID)"),
23719
+ taskDescription: external_exports.string().describe('Description of the task \u2014 e.g. "change the welcome message on the home page"')
23720
+ },
23721
+ async ({ workspaceId, workspaceName, taskDescription }) => {
23722
+ try {
23723
+ const id = await resolveWorkspaceId(workspaceId, workspaceName);
23724
+ const result = await api.intelligence.contextForTask({
23725
+ workspaceId: id,
23726
+ taskDescription
23727
+ });
23728
+ return success(result.context);
23729
+ } catch (error2) {
23730
+ return formatError2(error2);
23731
+ }
23732
+ }
23733
+ );
23734
+ server2.tool(
23735
+ "get_file_map",
23736
+ "Get a compact map of every file in the codebase with its category and key exports. Useful for understanding project structure at a glance.",
23737
+ {
23738
+ workspaceId: external_exports.string().uuid().optional().describe("Workspace ID"),
23739
+ workspaceName: external_exports.string().optional().describe("Workspace name (alternative to ID)")
23740
+ },
23741
+ async ({ workspaceId, workspaceName }) => {
23742
+ try {
23743
+ const id = await resolveWorkspaceId(workspaceId, workspaceName);
23744
+ const result = await api.intelligence.fileMap({ workspaceId: id });
23745
+ const lines = [
23746
+ `# File Map (${Object.keys(result.tree).length} files)`,
23747
+ `Tech stack: ${result.techStack.frameworks.join(", ")} | ${result.techStack.languages.join(", ")}`,
23748
+ ""
23749
+ ];
23750
+ for (const [path3, desc] of Object.entries(result.tree)) {
23751
+ lines.push(`${path3} \u2014 ${desc}`);
23752
+ }
23753
+ return success(lines.join("\n"));
23754
+ } catch (error2) {
23755
+ return formatError2(error2);
23756
+ }
23757
+ }
23758
+ );
23759
+ server2.tool(
23760
+ "get_file_deps",
23761
+ "Get the dependency graph for a specific file \u2014 what it imports (dependencies) or what imports it (dependents).",
23762
+ {
23763
+ workspaceId: external_exports.string().uuid().optional().describe("Workspace ID"),
23764
+ workspaceName: external_exports.string().optional().describe("Workspace name (alternative to ID)"),
23765
+ filePath: external_exports.string().describe('Relative file path \u2014 e.g. "src/components/task-card.tsx"'),
23766
+ direction: external_exports.enum(["dependents", "dependencies"]).optional().describe('Direction: "dependents" (what imports this file) or "dependencies" (what this file imports). Default: dependents')
23767
+ },
23768
+ async ({ workspaceId, workspaceName, filePath, direction }) => {
23769
+ try {
23770
+ const id = await resolveWorkspaceId(workspaceId, workspaceName);
23771
+ const result = await api.intelligence.deps({
23772
+ workspaceId: id,
23773
+ filePath,
23774
+ direction
23775
+ });
23776
+ const label = direction === "dependencies" ? "depends on" : "is imported by";
23777
+ if (result.files.length === 0) {
23778
+ return success(`\`${filePath}\` ${label} no other files`);
23779
+ }
23780
+ const lines = [`\`${filePath}\` ${label}:`];
23781
+ for (const f of result.files) {
23782
+ lines.push(` - \`${f}\``);
23783
+ }
23784
+ return success(lines.join("\n"));
23785
+ } catch (error2) {
23786
+ return formatError2(error2);
23787
+ }
23788
+ }
23789
+ );
23790
+ }
23791
+
23542
23792
  // src/tools/index.ts
23543
23793
  function registerAllTools(server2) {
23544
23794
  registerWorkspaceTools(server2);
@@ -23549,6 +23799,7 @@ function registerAllTools(server2) {
23549
23799
  registerSearchTools(server2);
23550
23800
  registerTaskTools(server2);
23551
23801
  registerActivityTools(server2);
23802
+ registerIntelligenceTools(server2);
23552
23803
  }
23553
23804
 
23554
23805
  // src/index.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chapterai/mcp",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Chapter MCP server — gives AI agents access to Chapter projects, files, changes, and history",
5
5
  "type": "module",
6
6
  "bin": {