@chapterai/mcp 0.1.4 → 0.1.7
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.
- package/dist/index.js +64 -21
- 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
|
|
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
|
|
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({
|
|
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,
|
|
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({
|
|
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")}`);
|
|
@@ -23714,15 +23735,37 @@ ${lines.join("\n")}`);
|
|
|
23714
23735
|
}
|
|
23715
23736
|
}
|
|
23716
23737
|
);
|
|
23738
|
+
server2.tool(
|
|
23739
|
+
"answer_about_codebase",
|
|
23740
|
+
'Ask a question about the codebase and get a complete, cited answer in one call. Reads the most relevant ~8 files server-side and returns a synthesized markdown answer with inline path:line citations on every concrete claim. ASK FIRST for any "how does X work", "where is X created/used across the codebase", or "walk me through the flow from A to B" question \u2014 this replaces the typical query_codebase + 4-6 read_file slices loop with a single round trip. Only fall back to read_file when you need verbatim code beyond what the answer cites.',
|
|
23741
|
+
{
|
|
23742
|
+
workspaceId: external_exports.string().uuid().optional().describe("Workspace ID"),
|
|
23743
|
+
workspaceName: external_exports.string().optional().describe("Workspace name (alternative to ID)"),
|
|
23744
|
+
taskDescription: external_exports.string().describe('Question or task \u2014 e.g. "how does the permission system work?", "where is sessionEnded emitted across the codebase?", "walk me through what happens when a user clicks Apply Changes"')
|
|
23745
|
+
},
|
|
23746
|
+
async ({ workspaceId, workspaceName, taskDescription }) => {
|
|
23747
|
+
try {
|
|
23748
|
+
const id = await resolveWorkspaceId(workspaceId, workspaceName);
|
|
23749
|
+
const result = await api.intelligence.contextForTask({
|
|
23750
|
+
workspaceId: id,
|
|
23751
|
+
taskDescription
|
|
23752
|
+
});
|
|
23753
|
+
return success(result.context);
|
|
23754
|
+
} catch (error2) {
|
|
23755
|
+
return formatError2(error2);
|
|
23756
|
+
}
|
|
23757
|
+
}
|
|
23758
|
+
);
|
|
23717
23759
|
server2.tool(
|
|
23718
23760
|
"get_codebase_context",
|
|
23719
|
-
"Ask a question about the codebase
|
|
23761
|
+
"(deprecated alias for answer_about_codebase) Ask a question about the codebase and get a cited answer. This name will be removed in 0.3.0; switch your callsites to answer_about_codebase.",
|
|
23720
23762
|
{
|
|
23721
23763
|
workspaceId: external_exports.string().uuid().optional().describe("Workspace ID"),
|
|
23722
23764
|
workspaceName: external_exports.string().optional().describe("Workspace name (alternative to ID)"),
|
|
23723
|
-
taskDescription: external_exports.string().describe(
|
|
23765
|
+
taskDescription: external_exports.string().describe("Question or task description")
|
|
23724
23766
|
},
|
|
23725
23767
|
async ({ workspaceId, workspaceName, taskDescription }) => {
|
|
23768
|
+
console.error("get_codebase_context is deprecated; use answer_about_codebase");
|
|
23726
23769
|
try {
|
|
23727
23770
|
const id = await resolveWorkspaceId(workspaceId, workspaceName);
|
|
23728
23771
|
const result = await api.intelligence.contextForTask({
|