submit_diff_review
Submit a git diff for code review to a chosen provider, with optional base ref and prompt. Auto-detects diff range from working tree or branch.
Instructions
Send a code-review job: the MCP server runs git diff inside repo_path and forwards the diff to the chosen provider. The diff content never appears in the LLM's output tokens, only the short tool call does. When base is omitted, auto-detects: dirty working tree -> diff against HEAD; clean tree with main/master/origin-HEAD found -> ${detected}...HEAD; otherwise falls back to diff against HEAD. Pass base explicitly (e.g. "main", a tag, or a SHA) to force a ${base}...HEAD PR-style range. Optional prompt is prepended above the diff so reviewers can scope the review. Default capability is "review" - override if the provider advertises a different tag.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| provider_npub | Yes | ||
| capability | No | Capability tag advertised by the reviewer. Override if not "review". | review |
| repo_path | No | Path to the git repo. Absolute or relative to the MCP server's working directory. | . |
| base | No | Optional base ref (branch, tag, SHA). When set, diffs ${base}...HEAD. When omitted, auto-detects working-tree vs main/master/origin-HEAD. | |
| prompt | No | Optional instructions prepended above the diff (e.g. "focus on auth flow"). | |
| kind_offset | No | ||
| timeout_secs | No | ||
| max_price_lamports | No |
Implementation Reference
- The `submit_diff_review` tool handler: computes a git diff (via computeGitDiff), composes the prompt + diff as the job input payload, then delegates to executeSubmitAndPay for the full submit/pay/await flow.
defineTool({ name: 'submit_diff_review', description: 'Send a code-review job: the MCP server runs `git diff` inside repo_path and forwards ' + "the diff to the chosen provider. The diff content never appears in the LLM's output " + 'tokens, only the short tool call does. ' + 'When base is omitted, auto-detects: dirty working tree -> diff against HEAD; ' + 'clean tree with main/master/origin-HEAD found -> ${detected}...HEAD; otherwise ' + 'falls back to diff against HEAD. Pass base explicitly (e.g. "main", a tag, or a SHA) ' + 'to force a `${base}...HEAD` PR-style range. ' + 'Optional `prompt` is prepended above the diff so reviewers can scope the review. ' + 'Default capability is "review" - override if the provider advertises a different tag.', schema: SubmitDiffReviewSchema, async handler(ctx, input) { ctx.toolRateLimiter.check(); checkLen('provider_npub', input.provider_npub, MAX_NPUB_LEN); let diffResult; try { diffResult = await computeGitDiff(input.repo_path, input.base); } catch (e) { return errorResult(e instanceof Error ? e.message : String(e)); } // Compose payload: optional prompt then a fenced diff block with the // resolved range so the provider knows what was actually compared. const promptBlock = input.prompt.trim().length > 0 ? `${input.prompt.trim()}\n\n` : ''; const payload = `${promptBlock}--- git diff (${diffResult.describedRange}) ---\n${diffResult.diff}`; if (payload.length > MAX_INPUT_LEN) { return errorResult( `Combined prompt + diff is ${payload.length} chars (max ${MAX_INPUT_LEN}). ` + `Shorten the prompt or pass a narrower base.`, ); } const agent = ctx.active(); return executeSubmitAndPay(ctx, agent, { input: payload, providerNpub: input.provider_npub, providerPubkey: decodeNpub(input.provider_npub), capability: input.capability, dTag: toDTag(input.capability), kindOffset: input.kind_offset, timeoutMs: Math.min(input.timeout_secs, MAX_TIMEOUT_SECS) * 1000, maxPriceLamports: input.max_price_lamports, }); }, - Zod schema for submit_diff_review: validates provider_npub, capability, repo_path, base (optional), prompt, kind_offset, timeout_secs, and max_price_lamports.
const SubmitDiffReviewSchema = z.object({ provider_npub: z.string(), capability: z .string() .min(1) .max(64) .default('review') .describe('Capability tag advertised by the reviewer. Override if not "review".'), repo_path: z .string() .min(1) .max(4096) .default('.') .describe("Path to the git repo. Absolute or relative to the MCP server's working directory."), base: z .string() .max(200) .optional() .describe( 'Optional base ref (branch, tag, SHA). When set, diffs ${base}...HEAD. When ' + 'omitted, auto-detects working-tree vs main/master/origin-HEAD.', ), prompt: z .string() .max(MAX_INPUT_LEN) .default('') .describe('Optional instructions prepended above the diff (e.g. "focus on auth flow").'), kind_offset: z.number().int().min(0).max(999).default(DEFAULT_KIND_OFFSET), timeout_secs: z.number().int().min(1).max(600).default(300), max_price_lamports: z.number().int().optional(), }); - packages/mcp/src/server.ts:32-45 (registration)All tools aggregated in server.ts - customerTools array (which includes submit_diff_review) is spread into the allTools registry and registered with the MCP server.
const allTools: ToolDefinition[] = [ ...discoveryTools, ...customerTools, ...walletTools, ...dashboardTools, ...agentTools, ...feedbackContactsTools, ...policiesTools, ]; // fail at startup if any tool name is duplicated or empty. A silent overwrite in // `toolMap` would cause the LLM to see two tools with the same name but only one being // callable. const toolMap = new Map<string, ToolDefinition>(); - The computeGitDiff helper function: handles base detection (auto-detecting main/master/origin-HEAD), runs git diff, and returns the diff text with a described range string.
export async function computeGitDiff(repoPath: string, base?: string): Promise<GitDiffResult> { if (repoPath.length > MAX_INPUT_PATH_LEN) { throw new Error(`repo_path too long: ${repoPath.length} chars (max ${MAX_INPUT_PATH_LEN}).`); } const absRepo = isAbsolute(repoPath) ? repoPath : resolvePath(process.cwd(), repoPath); await assertGitRepo(absRepo); let args: string[]; let describedRange: string; if (base) { args = ['diff', `${base}...HEAD`]; describedRange = `${base}...HEAD`; } else if (await isDirty(absRepo)) { args = ['diff', 'HEAD']; describedRange = 'HEAD (working tree, uncommitted changes)'; } else { const detected = await detectDefaultBase(absRepo); if (detected) { args = ['diff', `${detected}...HEAD`]; describedRange = `${detected}...HEAD`; } else { args = ['diff', 'HEAD']; describedRange = 'HEAD (no main/master detected)'; } } const diff = await execGit(absRepo, args); if (diff.trim().length === 0) { throw new Error( `No changes in range ${describedRange}. Nothing to review - commit work, ` + `pass an explicit "base", or check the repo path.`, ); } if (diff.length > MAX_INPUT_LEN) { throw new Error( `Diff for range ${describedRange} is ${diff.length} chars (max ${MAX_INPUT_LEN}). ` + `Pass a narrower "base" or split the review.`, ); } return { diff, describedRange }; } - The executeSubmitAndPay shared helper function used by submit_diff_review (and submit_and_pay_job, submit_and_pay_job_from_file) to handle the complete submit->pay->await flow.
async function executeSubmitAndPay( ctx: AgentContext, agent: AgentInstance, params: SubmitAndPayParams, ): Promise<ToolResult> { // Pre-ping: refuse to submit to an unreachable provider. The 30s pong cache // in PingService means that if the caller just ran search_agents, this is a // free in-memory lookup. A hard error here avoids wasting a 120-300s timeout // and, for paid jobs, avoids publishing a NIP-90 request that nobody will ever // service. const ping = await agent.client.ping.pingAgent(params.providerPubkey, PRE_PING_TIMEOUT_MS); if (!ping.online) { return errorResult( `Provider ${params.providerNpub} is offline. ` + `Run search_agents to find currently-online providers.`, ); } // resolve expected Solana recipient from the provider's capability card // BEFORE submitting the job. If the provider is unknown on-network, fail fast. const providers = await agent.client.discovery.fetchAgents(agent.network); const provider = providers.find((a) => a.npub === params.providerNpub); // if the provider is not in the current discovery snapshot, refuse // to submit. Previously we fell through with `expectedRecipient = undefined`, // which silently disabled the recipient-match check inside `validatePaymentRequest` // and let a malicious actor redirect funds. Free providers without Solana payment // are still allowed - the no-wallet path in makePaymentFeedbackHandler handles them. if (!provider) { return errorResult( `Provider ${params.providerNpub} not found on ${agent.network}. ` + `Refresh discovery (e.g. search_agents) or verify the npub is correct.`, ); } const expectedRecipient = providerSolanaAddress(provider, params.dTag); if (agent.solanaKeypair && !expectedRecipient) { // Customer has a wallet (intends to pay), but the provider advertised no Solana // recipient for this capability. We cannot verify where funds would go - refuse. return errorResult( `Provider "${params.providerNpub}" has no Solana payment address for ` + `capability "${params.capability}". Cannot verify payment recipient - refusing ` + `to proceed. Ask the provider to publish a capability card with a payment address.`, ); } const buyerWallet = agent.solanaKeypair?.publicKey; if (buyerWallet && expectedRecipient && buyerWallet === expectedRecipient) { return errorResult( `Cannot buy from yourself - your agent's Solana wallet (${buyerWallet}) ` + `matches the provider's payment address. Use a different agent or provider.`, ); } const submittedAt = Date.now(); const jobId = await agent.client.marketplace.submitJobRequest(agent.identity, { input: params.input, capability: params.dTag, providerPubkey: params.providerPubkey, kindOffset: params.kindOffset, }); let paymentSig: string | undefined; let paidAmountSubunits: bigint | undefined; let paidAssetKey: string | undefined; let paymentWarnings: string[] = []; try { const result = await awaitJobResult<string>( agent, {} as never, ({ resolve, reject }) => { const payHandler = makePaymentFeedbackHandler({ ctx, agent, jobId, providerPubkey: params.providerPubkey, expectedRecipient, maxPriceLamports: params.maxPriceLamports, resolveNoWallet: resolve, resolveResult: resolve, rejectPayment: reject, onPaid: (sig, warnings, amount, assetKey) => { paymentSig = sig; paidAmountSubunits = amount; paidAssetKey = assetKey; paymentWarnings = warnings; for (const line of warnings) { logger.warn({ event: 'session_spend_threshold', agent: agent.name }, line); } }, }); return { jobEventId: jobId, providerPubkey: params.providerPubkey, customerPublicKey: agent.identity.publicKey, callbacks: { onResult(content: string) { const kind = isLikelyBase64(content) ? ('binary' as const) : ('text' as const); const sanitized = sanitizeUntrusted(content, kind); payHandler.onResultReceived(`Job completed.\n\n${sanitized.text}`); }, onFeedback: payHandler.onFeedback, onError(error: string) { reject(new Error(`Job error: ${error}`)); }, }, timeoutMs: params.timeoutMs, customerSecretKey: agent.identity.secretKey, }; }, params.timeoutMs + 5_000, ); await recordJobOutcome(agent, { jobEventId: jobId, capability: params.dTag, providerPubkey: params.providerPubkey, providerName: clipProviderName(provider.name), paidAmountSubunits: paidAmountSubunits?.toString(), assetKey: paidAssetKey, status: 'completed', submittedAt, completedAt: Date.now(), resultPreview: result.slice(0, RESULT_PREVIEW_MAX_LEN), paymentSig, }); const warningBlock = paymentWarnings.length > 0 ? `${paymentWarnings.join('\n')}\n` : ''; const tip = buildJobCompletionTip(jobId, params.providerNpub); return textResult(`${warningBlock}event_id=${jobId}\n${result}${tip}`); } catch (e) { const msg = e instanceof Error ? e.message : String(e); await recordJobOutcome(agent, { jobEventId: jobId, capability: params.dTag, providerPubkey: params.providerPubkey, providerName: clipProviderName(provider.name), paidAmountSubunits: paidAmountSubunits?.toString(), assetKey: paidAssetKey, status: classifyJobFailure(msg), submittedAt, completedAt: Date.now(), paymentSig, }); const paid = paymentSig ? ` Payment already sent (sig=${paymentSig}) - use get_job_result with event_id="${jobId}" to retrieve once ready.` : ''; const warningBlock = paymentWarnings.length > 0 ? `${paymentWarnings.join('\n')}\n` : ''; return errorResult(`${warningBlock}Job ${jobId} failed: ${msg}.${paid}`); } }