@chapterai/mcp 0.1.4 → 0.1.5

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 +40 -19
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -23567,6 +23567,15 @@ ${lines.join("\n")}`);
23567
23567
  }
23568
23568
 
23569
23569
  // src/tools/intelligence.ts
23570
+ function renderSnippet(snippet) {
23571
+ if (!snippet) return "";
23572
+ const padWidth = Math.max(4, String(snippet.endLine).length);
23573
+ const body = snippet.lines.map((line, i) => `${String(snippet.startLine + i).padStart(padWidth, " ")} | ${line}`).join("\n");
23574
+ return `
23575
+ \`\`\`
23576
+ ${body}
23577
+ \`\`\``;
23578
+ }
23570
23579
  function registerIntelligenceTools(server2) {
23571
23580
  server2.tool(
23572
23581
  "scan_codebase",
@@ -23608,48 +23617,49 @@ function registerIntelligenceTools(server2) {
23608
23617
  );
23609
23618
  server2.tool(
23610
23619
  "query_codebase",
23611
- "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).",
23620
+ "Search the codebase index for files, symbols, routes, endpoints, and copy matching a query. Returns ranked results with file paths, line numbers, and inline source snippets so you usually don't need a follow-up read_file call.",
23612
23621
  {
23613
23622
  workspaceId: external_exports.string().uuid().optional().describe("Workspace ID"),
23614
23623
  workspaceName: external_exports.string().optional().describe("Workspace name (alternative to ID)"),
23615
23624
  query: external_exports.string().describe('Search query \u2014 e.g. "task creation", "auth middleware", "welcome page"'),
23616
- limit: external_exports.number().optional().describe("Max results per category (default 20)")
23625
+ limit: external_exports.number().optional().describe("Max results per category (default 20)"),
23626
+ contextLines: external_exports.number().int().min(0).max(20).default(6).describe("Lines of source to include around each hit. 0 disables snippets.")
23617
23627
  },
23618
- async ({ workspaceId, workspaceName, query, limit }) => {
23628
+ async ({ workspaceId, workspaceName, query, limit, contextLines }) => {
23619
23629
  try {
23620
23630
  const id = await resolveWorkspaceId(workspaceId, workspaceName);
23621
- const result = await api.intelligence.query({ workspaceId: id, query, limit });
23631
+ const result = await api.intelligence.query({ workspaceId: id, query, limit, contextLines });
23622
23632
  const sections = [];
23623
23633
  if (result.files.length > 0) {
23624
23634
  sections.push("## Files");
23625
23635
  for (const f of result.files) {
23626
23636
  const exports = f.exports.length > 0 ? ` (exports: ${f.exports.slice(0, 3).join(", ")})` : "";
23627
- sections.push(`- \`${f.path}\` [${f.category}]${exports}`);
23637
+ sections.push(`- \`${f.path}\` [${f.category}]${exports}${renderSnippet(f.snippet)}`);
23628
23638
  }
23629
23639
  }
23630
23640
  if (result.symbols.length > 0) {
23631
23641
  sections.push("\n## Symbols");
23632
23642
  for (const s of result.symbols) {
23633
23643
  const sig = s.signature ? ` \u2014 \`${s.signature}\`` : "";
23634
- sections.push(`- \`${s.name}\` (${s.kind}) at \`${s.filePath}:${s.line}\`${sig}`);
23644
+ sections.push(`- \`${s.name}\` (${s.kind}) at \`${s.filePath}:${s.line}\`${sig}${renderSnippet(s.snippet)}`);
23635
23645
  }
23636
23646
  }
23637
23647
  if (result.copy.length > 0) {
23638
23648
  sections.push("\n## Copy/Text");
23639
23649
  for (const c of result.copy) {
23640
- sections.push(`- "${c.text}" at \`${c.filePath}:${c.line}\` in ${c.context}`);
23650
+ sections.push(`- "${c.text}" at \`${c.filePath}:${c.line}\` in ${c.context}${renderSnippet(c.snippet)}`);
23641
23651
  }
23642
23652
  }
23643
23653
  if (result.routes.length > 0) {
23644
23654
  sections.push("\n## Routes");
23645
23655
  for (const r of result.routes) {
23646
- sections.push(`- ${r.method ?? "ANY"} \`${r.path}\` \u2192 ${r.handler} at \`${r.filePath}:${r.line}\``);
23656
+ sections.push(`- ${r.method ?? "ANY"} \`${r.path}\` \u2192 ${r.handler} at \`${r.filePath}:${r.line}\`${renderSnippet(r.snippet)}`);
23647
23657
  }
23648
23658
  }
23649
23659
  if (result.endpoints.length > 0) {
23650
23660
  sections.push("\n## API Endpoints");
23651
23661
  for (const e of result.endpoints) {
23652
- sections.push(`- \`${e.router ? e.router + "." : ""}${e.name}\` (${e.type}) at \`${e.filePath}:${e.line}\``);
23662
+ sections.push(`- \`${e.router ? e.router + "." : ""}${e.name}\` (${e.type}) at \`${e.filePath}:${e.line}\`${renderSnippet(e.snippet)}`);
23653
23663
  }
23654
23664
  }
23655
23665
  if (sections.length === 0) {
@@ -23663,24 +23673,30 @@ function registerIntelligenceTools(server2) {
23663
23673
  );
23664
23674
  server2.tool(
23665
23675
  "find_symbol",
23666
- "Find a specific function, class, component, type, or other symbol by name. Returns exact file path and line number.",
23676
+ "Find a specific function, class, component, type, or other symbol by name. Returns exact file path, line number, and an inline source snippet so the symbol body is right there.",
23667
23677
  {
23668
23678
  workspaceId: external_exports.string().uuid().optional().describe("Workspace ID"),
23669
23679
  workspaceName: external_exports.string().optional().describe("Workspace name (alternative to ID)"),
23670
23680
  name: external_exports.string().describe('Symbol name to search for \u2014 e.g. "TaskCreateInline", "authorizeWorkspaceAccess"'),
23671
- kind: external_exports.string().optional().describe("Filter by kind: function, class, component, type, interface, enum, hook, struct, method")
23681
+ kind: external_exports.string().optional().describe("Filter by kind: function, class, component, type, interface, enum, hook, struct, method"),
23682
+ contextLines: external_exports.number().int().min(0).max(20).default(8).describe("Lines of source to include around each hit. 0 disables snippets.")
23672
23683
  },
23673
- async ({ workspaceId, workspaceName, name, kind }) => {
23684
+ async ({ workspaceId, workspaceName, name, kind, contextLines }) => {
23674
23685
  try {
23675
23686
  const id = await resolveWorkspaceId(workspaceId, workspaceName);
23676
- const results = await api.intelligence.findSymbol({ workspaceId: id, name, kind });
23687
+ const results = await api.intelligence.findSymbol({
23688
+ workspaceId: id,
23689
+ name,
23690
+ kind,
23691
+ contextLines
23692
+ });
23677
23693
  if (results.length === 0) {
23678
23694
  return success(`No symbol found matching "${name}"${kind ? ` (kind: ${kind})` : ""}`);
23679
23695
  }
23680
23696
  const lines = results.map((s) => {
23681
23697
  const sig = s.signature ? `
23682
23698
  ${s.signature}` : "";
23683
- return `- \`${s.name}\` (${s.kind}) at \`${s.filePath}:${s.line}\`${s.exported ? " [exported]" : ""}${sig}`;
23699
+ return `- \`${s.name}\` (${s.kind}) at \`${s.filePath}:${s.line}\`${s.exported ? " [exported]" : ""}${sig}${renderSnippet(s.snippet)}`;
23684
23700
  });
23685
23701
  return success(`Found ${results.length} match(es):
23686
23702
  ${lines.join("\n")}`);
@@ -23691,21 +23707,26 @@ ${lines.join("\n")}`);
23691
23707
  );
23692
23708
  server2.tool(
23693
23709
  "find_copy",
23694
- "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.",
23710
+ "Find user-facing text/copy in the codebase by content. Returns the file path, line number, surrounding component context, and an inline JSX/template snippet.",
23695
23711
  {
23696
23712
  workspaceId: external_exports.string().uuid().optional().describe("Workspace ID"),
23697
23713
  workspaceName: external_exports.string().optional().describe("Workspace name (alternative to ID)"),
23698
- text: external_exports.string().describe('Text to search for \u2014 e.g. "Welcome to Chapter", "Sign in", "No tasks yet"')
23714
+ text: external_exports.string().describe('Text to search for \u2014 e.g. "Welcome to Chapter", "Sign in", "No tasks yet"'),
23715
+ contextLines: external_exports.number().int().min(0).max(20).default(4).describe("Lines of source to include around each hit. 0 disables snippets.")
23699
23716
  },
23700
- async ({ workspaceId, workspaceName, text }) => {
23717
+ async ({ workspaceId, workspaceName, text, contextLines }) => {
23701
23718
  try {
23702
23719
  const id = await resolveWorkspaceId(workspaceId, workspaceName);
23703
- const results = await api.intelligence.findCopy({ workspaceId: id, text });
23720
+ const results = await api.intelligence.findCopy({
23721
+ workspaceId: id,
23722
+ text,
23723
+ contextLines
23724
+ });
23704
23725
  if (results.length === 0) {
23705
23726
  return success(`No copy found matching "${text}"`);
23706
23727
  }
23707
23728
  const lines = results.map(
23708
- (c) => `- "${c.text}" at \`${c.filePath}:${c.line}\` in \`${c.context}\` (${c.type})`
23729
+ (c) => `- "${c.text}" at \`${c.filePath}:${c.line}\` in \`${c.context}\` (${c.type})${renderSnippet(c.snippet)}`
23709
23730
  );
23710
23731
  return success(`Found ${results.length} match(es):
23711
23732
  ${lines.join("\n")}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chapterai/mcp",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Chapter MCP server — gives AI agents access to Chapter projects, files, changes, and history",
5
5
  "type": "module",
6
6
  "bin": {