AI agents and MCP
Give an agent the API as a tool, through a function-calling definition or the hosted Silvertext MCP server, so it can check a draft and apply the fixes.
The API was shaped for agents as much as for apps: one submit, one poll, one report whose findings carry fixes, and JSON everywhere. Two ways in.
As a tool in your agent
Define two tools, submit_check and read_check, and let the model chain them. The submit tool takes the text and options; the read tool takes the id and returns the summary or the findings. Keep polling on your side (the tool waits for the check) so the model sees one round trip.
import { Silvertext } from './silvertext';
const st = new Silvertext();
export const tools = [
{
name: 'check_writing',
description:
'Check a document for plagiarism, grammar and spelling, citation problems and AI-written content. Returns scores and a list of findings, each with a suggested fix.',
input_schema: {
type: 'object',
properties: {
text: { type: 'string', description: 'The document text.' },
checks: {
type: 'array',
items: {
type: 'string',
enum: ['plagiarism', 'grammarSpelling', 'citations', 'aiContent', 'style'],
},
description: 'Which checks to run. Defaults to all.',
},
citationStyle: { type: 'string', enum: ['APA', 'MLA', 'Chicago'] },
},
required: ['text'],
},
},
];
export async function runTool(name: string, input: any) {
if (name !== 'check_writing') throw new Error(`unknown tool ${name}`);
const all = ['plagiarism', 'grammarSpelling', 'citations', 'aiContent', 'style'];
const options = Object.fromEntries(
all.map((k) => [k, !input.checks || input.checks.includes(k)]),
);
const { id } = await st.createCheck({
text: input.text,
options,
citationStyle: input.citationStyle,
});
const summary = await st.waitForCheck(id);
if (summary.status !== 'done')
return { status: summary.status, reason: summary.rejection?.message };
const { report } = await st.getCheck<{ report: any }>(id, { include: ['issues', 'sources'] });
return {
scores: summary.scores,
findings: report.issues.map((i: any) => ({
category: i.category,
severity: i.severity,
text: i.original?.text,
message: i.message,
fix: i.fix?.replacement ?? i.rephrase?.text,
source: i.sourceUrl,
})),
reportUrl: `https://app.silvertext.com/reports/${id}`,
};
}Trim the tool result to what the model needs. The full report with spans and matches runs to hundreds of kilobytes on a long document; the findings list above is a few kilobytes and is what an editing agent acts on.
Through the MCP server
The same checks are tools on a hosted MCP server at https://api.silvertext.com/mcp, so Claude, Cursor, VS Code and any other MCP client can check a draft with no code on your side. Streamable HTTP, stateless; the API key travels as a header on the connection, never inside a tool call.
claude mcp add --scope user --transport http silvertext https://api.silvertext.com/mcp \
--header "Authorization: Bearer $SILVERTEXT_API_KEY"Four tools, brand-prefixed so they never collide with another server's:
| Tool | What it does | Cost |
|---|---|---|
silvertext_submit_check | Submits text or a base64 file with the same options and citationStyle as the REST body, waits up to wait_seconds (0 to 55, default 45) for the result, and answers a one-line verdict plus the scores and issues with fixes (detail: "full" for spans, matches and sources). A check still running comes back with its check_id. Takes an idempotency_key, so a retried call never starts a second check. | 150 credits per 250 words |
silvertext_get_check | Status and progress while a check runs; the report once it is done, trimmed to scores and issues unless detail or include asks for more. | free |
silvertext_list_checks | The 50 most recent checks with status and scores. | free |
silvertext_get_usage | Credits remaining (plan period plus purchased pool) and where to top up. | free |
Every answer carries credits_remaining; a refusal comes back as a tool error in the REST error code's words (quota_exceeded says how many credits are left and where to buy more, rate_limited says when to retry), so the agent can relay it. The key's scopes apply exactly as on REST: a checks:read key can read and list but a submit answers insufficient_scope.
Reading the result as an agent
scores.plagiarismabove a threshold you choose means the draft needs sources or rewriting; thesourceslist has the URLs and citation metadata to cite them.scores.aiContentis a likelihood, not a verdict. Show it with its sentence-level findings rather than acting on the number alone.- Findings carry offsets into the submitted text. Apply fixes from the end of the document backwards, or hand the model the
textplus the findings and let it rewrite. - A
rejectedcheck has arejection.codeworth surfacing (too_long,unsupported_language); an agent should not retry those.