Spec Driven Development
MCP Server that facilitates spec-driven development workflows, not just Vibe Coding.
제작자가 쓴 설명(영어 원문)
The record layer for the machine age: counter-signed receipts and agent action records.
이 세 가지는 절대 하나의 점수로 합치지 않아요. 의견, 측정, 인기는 서로 다른 것이니까요.
이 서버는 아직 쉬운 말로 된 요약을 쓰지 못했어요. 아래는 레지스트리에서 읽어 온 사실이에요.
쓰고 있는 AI 앱을 고른 다음 설정을 복사하세요.
TERSIGN_SELLER_KEY, TERSIGN_ISSUER_NAME, TERSIGN_ISSUER_JURISDICTION, TERSIGN_ISSUER_TAX_ID, TERSIGN_LEDGER_URL, TERSIGN_LEDGER_API_KEY, TERSIGN_LEDGER_SELLER_ID비밀로 표시된 값은 내 계정의 열쇠예요. 절대 다른 사람과 공유하거나 채팅에 붙여 넣지 마세요.
필요한 것
어떤 앱을 쓰세요?
위에서 앱을 고르세요. 기억해 두었다가 다음부터는 버튼에 “…에 설치”라고 표시해요.
Claude Desktop → Settings → Developer → Edit Config를 열고 claude_desktop_config.json에 이 내용을 붙여 넣으세요
{
"mcpServers": {
"evidence": {
"command": "npx",
"args": [
"-y",
"tersign"
],
"env": {
"TERSIGN_SELLER_KEY": "your-value",
"TERSIGN_ISSUER_NAME": "your-value",
"TERSIGN_ISSUER_JURISDICTION": "your-value",
"TERSIGN_ISSUER_TAX_ID": "your-value",
"TERSIGN_LEDGER_URL": "your-value",
"TERSIGN_LEDGER_API_KEY": "your-value",
"TERSIGN_LEDGER_SELLER_ID": "your-value"
}
}
}
}터미널에서 이 명령어를 실행하세요
claude mcp add evidence --env TERSIGN_SELLER_KEY=your-value --env TERSIGN_ISSUER_NAME=your-value --env TERSIGN_ISSUER_JURISDICTION=your-value --env TERSIGN_ISSUER_TAX_ID=your-value --env TERSIGN_LEDGER_URL=your-value --env TERSIGN_LEDGER_API_KEY=your-value --env TERSIGN_LEDGER_SELLER_ID=your-value -- npx -y tersign실행하기 전에 빈 값을 채워 주세요.
프로젝트의 .cursor/mcp.json 또는 ~/.cursor/mcp.json에 붙여 넣으세요
{
"mcpServers": {
"evidence": {
"command": "npx",
"args": [
"-y",
"tersign"
],
"env": {
"TERSIGN_SELLER_KEY": "your-value",
"TERSIGN_ISSUER_NAME": "your-value",
"TERSIGN_ISSUER_JURISDICTION": "your-value",
"TERSIGN_ISSUER_TAX_ID": "your-value",
"TERSIGN_LEDGER_URL": "your-value",
"TERSIGN_LEDGER_API_KEY": "your-value",
"TERSIGN_LEDGER_SELLER_ID": "your-value"
}
}
}
}브라우저가 앱을 열지 물어본 다음, 앱이 설정을 보여 주고 확인을 요청해요. 키 값은 비워 두니 직접 입력하세요.
프로젝트의 .vscode/mcp.json에 붙여 넣으세요
{
"servers": {
"evidence": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"tersign"
],
"env": {
"TERSIGN_SELLER_KEY": "your-value",
"TERSIGN_ISSUER_NAME": "your-value",
"TERSIGN_ISSUER_JURISDICTION": "your-value",
"TERSIGN_ISSUER_TAX_ID": "your-value",
"TERSIGN_LEDGER_URL": "your-value",
"TERSIGN_LEDGER_API_KEY": "your-value",
"TERSIGN_LEDGER_SELLER_ID": "your-value"
}
}
}
}브라우저가 앱을 열지 물어본 다음, 앱이 설정을 보여 주고 확인을 요청해요. 키 값은 비워 두니 직접 입력하세요.
이 서버는 내 컴퓨터에서 실행되는데, ChatGPT는 인터넷에 있는 서버에만 연결할 수 있어요. 다른 앱을 고르세요.
선택한 앱은 이 기기의 쿠키에만 저장돼요. 계정은 필요 없어요.
TERSIGN_ISSUER_NAME envTERSIGN_ISSUER_JURISDICTION envTERSIGN_ISSUER_TAX_ID envTERSIGN_LEDGER_URL envTERSIGN_LEDGER_SELLER_ID env이 설정은 제작자의 레지스트리 정보로 만들었어요. README와 다르면 README를 따르세요.
내 컴퓨터에서 실행돼요. 설치하면 AI 앱에 도구 목록이 나타나요.
누구나 볼 수 있는 정보를 점검했고, 코드는 읽지 않았어요. 해당하지 않는 항목은 개수에서 뺐어요. · 2026년 11월 7일 점검
레지스트리 이름이 GitHub 계정 tersignhq 기준으로 확인되었고, 이 계정이 저장소를 소유하고 있어요
아직 GitHub에서 이 저장소를 읽어 오지 않았어요
아직 GitHub에서 이 저장소를 읽어 오지 않았어요
내 컴퓨터에서 실행되는 서버라 인터넷 엔드포인트가 없어요
내 컴퓨터에서 실행되며, 대신 로컬 설정을 사용해요
내 컴퓨터에서 실행돼요. 도구 목록은 인터넷 엔드포인트가 있는 서버에서만 읽을 수 있어요
레지스트리에서 이 카테고리의 활성 서버 전체와 비교했어요. 스타는 게시자가 저장소를 소유한 경우에만 세요.
해당하는 기본 점검 1개 중 1개를 통과했어요. 코드는 읽지 않았어요. 키나 토큰을 넣기 전에 서버가 어떤 권한을 요구하는지 확인하고, 꼭 필요한 권한만 있는 키를 쓰세요.
입력해야 할 값: TERSIGN_SELLER_KEY, TERSIGN_LEDGER_API_KEY
내 컴퓨터에서 실행돼요. AI 앱이 필요할 때 실행하고, 데이터는 제작자의 서버를 거치지 않아요(서버 자체가 온라인 서비스를 호출하는 경우는 제외).
GitHub 저장소는 마지막으로 – 변경됐고, 최신 버전(0.6.8)은 11일 전 레지스트리에 올라왔어요.
Claude Desktop, Claude Code, Cursor, VS Code처럼 MCP를 지원하는 앱에서 쓸 수 있어요. 내 컴퓨터에 Node.js도 있어야 해요.
같은 카테고리에는: Spec Driven Development, Remote Desktop Commander, LexPact UK Contracts
같은 카테고리에서 다른 제작자가 만든 서버예요. 스타 순으로 정렬했어요.
카드 보는 법:★ GitHub 스타i세 기둥: 리뷰 · 점검 · 사용 정도i업데이트 = 최신 버전을 레지스트리에 공개한 날i
MCP Server that facilitates spec-driven development workflows, not just Vibe Coding.
Remote Desktop Commander: use files, terminal and processes on your own computers from any AI app.
Generate UK-law contracts: NDA, service, freelance, recruiter terms of business, IR35.
제작자의 저장소에서 쓰인 그대로 가져왔어요. PopNx MCP가 검토하거나 보증한 내용이 아니에요. HTML, 이미지, 스크립트는 제거했어요. 링크를 누르면 이 사이트를 벗어나요.
Tersign is the record layer for the machine age: what AI agents do and pay, counter-signed by a party outside the deal, anchored where no one can move it, checkable by anyone. *Machines can generate anything but the past.* Sellers sign EIP-712 receipts; Tersign chains them per seller and counter-signs every entry. When the dispute comes, the transcript is already sealed.
Venues rotate. The transcript endures.
No account. No API key. This is the genesis receipt, seq 1 on the production chain. It is a self-signed demo: Tersign signed it as seller and named its own key as payer, so its EIP-712 payload signature (domain {name: "x402 receipt", version: "1", chainId: 1}, per the x402 offer-and-receipt extension) recovers to the payload's own payer, 0x36f82906859E5B0bd076069f8cdfAea355358b14. /v1/genesis serves the record with the recipe for each of its signatures.
npx tersign verify 0xe5874f1ffe87f0a6dd9eb157730f67b86ee4538b125fe30fcc4e165213dd3fc4
ledger: https://tersign.ai
reports: found, counter-signed chain intact (seller tersign-first, seq 1, …) — not checked locally VALID (ledger-reported) — https://tersign.ai reports the record and its counter-signed chain; nothing was verified locally
npx tersign verify [--signer 0xaddr] [--ledger url] takes a receipt file or a digest.
--ledger. The EIP-712 signature is recovered, and --signer compares it with the issuer's address, which you take from the issuer through a channel you trust, never from the receipt. Without --signer the signer is reported UNAUTHENTICATED and the verdict reads VALID (signer UNAUTHENTICATED): recovery yields an address for any payload, so an edited receipt reaches that same line with a different address.published test key either way: anyone can produce that signature. Fields in the file that the signature does not cover are listed by name, and a signed field in another JSON type ("version": "1") is refused. The signature must be the one canonical encoding (0x + 130 lower-case hex digits, v 27/28, low-s): a re-encoding of a genuine signature (v 0/1, upper-case hex, the high-s twin) also recovers the issuer, under a different digest, so it is refused.{receipt, record}, or an evidence-bundle record file (records/NNNNNN.json, verdict qualified record artifact only: its chain fields are not checked here). Anything else that nests a receipt — a second receipt at the top level, or any other field beside it — is refused, because a reader would take those fields for the receipt that was checked. Duplicate keys and non-integer numbers are refused too.--ledger names another; the answer is that ledger's own counter-signed chain check, nothing in it is re-verified locally, and the verdict says so (VALID (ledger-reported)). The ledger consulted is always printed. The local check is the receipt file with --signer.Exit status: 0 valid (read the last line — for a file, a bare VALID means a bound, non-test-key signer on a receipt or {receipt, record}; a digest is always VALID (ledger-reported)), 1 invalid, 2 usage (an unknown or valueless flag, --signer with a digest, a missing or non-JSON file). Prefer raw HTTP? The same proof, no CLI:
curl https://tersign.ai/v1/receipts/0xe5874f1ffe87f0a6dd9eb157730f67b86ee4538b125fe30fcc4e165213dd3fc4/verify
Counter-signed evidence that your agent presented a disclosure — one command, no account:
npx tersign disclose "You are chatting with an AI assistant." --medium chat --agent-id my-agent
The text is digested locally (only the digest travels — data-minimization by construction). Your key signs the record; the ledger counter-signs it into a per-signer hash chain whose head is submitted for Bitcoin anchoring on a six-hourly cron. The first call self-provisions a free signer-keyed account bound set-once to your key, unless that key is already registered to an API-key ledger account (409: submit through that account) or the day's provisioning caps are reached (429). Key resolution: TERSIGN_SELLER_KEY env → macOS keychain tersign-signer → ~/.tersign/signer.key, created on first use. Free tier is quota- and rate-limited — limits. What this is: independently verifiable evidence the disclosure was attested at that time. What it is not: a compliance certification.
Every entry takes the same path: the seller signs the receipt (EIP-712, x402 offer-receipt extension) → Tersign computes the keccak256 canonical digest → the digest joins that seller's hash chain, each seq n bound to seq n−1 → the neutral ledger counter-signs (secp256k1) → anyone verifies, and any venue gets a serialized envelope.
Since 2026-08-28 each anchor stamps a chain commitment — an accumulator over every counter-signed link — so one anchored digest covers the whole prefix; rows anchored earlier bind the head record only and say so (subjectSchema).
graph LR
A["agent transaction x402"] --> B["seller-signed receipt EIP-712"] B --> C["canonical digest keccak256"] C --> D["per-seller hash chain seq n binds seq n−1"] D --> E["neutral counter-signature secp256k1 ledger"] E --> F["verifiable by anyone venue-formatted envelope"]
Diagram renders on GitHub. On npm, the paragraph above IS the diagram.
A refund record references the record it corrects by digest (refundOf). Disputes attach to the digest with objective reason codes. Party statements are structurally segregated behind an UNVERIFIED marker — the evidence stays prompt-injection-hardened.
npm i tersign
withAssure() wraps your x402 fetch handler. On a settled call it signs a receipt and a compliance-fields record with your key and merges both into the PAYMENT-RESPONSE header, the base64 JSON settlement response x402 wallets already read; the response body is left alone. When it cannot issue them (a settlement network that is neither CAIP-2 nor a v1 name in its table, such as "bsc", or a ledger error), the paid response goes out exactly as your handler returned it, with no receipt, and the error goes to onError (default: console.error); with idempotency on, a retry with the same payment id replays that response. On a 402 it adds compliance-fields to the PAYMENT-REQUIRED header. When the Assure is built with a ledger, the ledger counter-signs the receipt into your chain; the compliance-fields record is not counter-signed, and is bound to its receipt only by your own signature, which covers the receipt's digest. Without a ledger, both carry your signature alone.
import { privateKeyToAccount } from 'viem/accounts';
import { Assure, withAssure } from 'tersign';
const signer = privateKeyToAccount(process.env.TERSIGN_SELLER_KEY as 0x${string}); const assure = new Assure({ signer, issuer: { name: 'Example API Ltd', jurisdiction: 'HK' } }); export default { fetch: withAssure(app.fetch, { assure }) }; // app: your x402-protected Hono app
A wallet finds the receipt at extensions["offer-receipt"].info.receipt and the record at extensions["compliance-fields"].info.record of the decoded PAYMENT-RESPONSE (X-PAYMENT-RESPONSE on x402 v1). Sellers whose readers still parse the JSON body can pass legacyBodyPlacement: true for one more minor release.
The full register:
| Capability | In the record |
|---|---|
| Receipts | Seller-signed EIP-712 (x402 offer-receipt extension), keccak256 canonical digests |
withAssure() | x402 fetch-handler adapter — receipt + compliance-fields record in PAYMENT-RESPONSE on each paid call it can issue for, the paid response passed through unchanged when it cannot; compliance-fields advertised on 402 |
| Compliance-fields records | MINIMAL tier (Art 226b simplified-invoice content) via buildMinimalRecord · ledger exports format=art226b · format=s51c — mappings, not certifications |
| Action records | ActionRecordV1 — GDPR-minimized; states that an Art-50 disclosure was presented, with a digest of its text and never the text, signed by the deployer and counter-signed when it reaches the ledger; what it says is still the deployer's own report |
| Refunds | A refund record carries refundOf, the digest of the record it corrects · record_refund logs a pending refund entry on the ledger (not counter-signed); it moves no money |
| Disputes v0 | Objective reason codes, signed evidence submission, deterministic triage: fixed rules classify a duplicate charge (R1 reads receipts from one seller to one payer that share one settlement transaction as one payment) or an unanswered claim and record the result as data, not an adjudication; anything else is marked escalated, for an external venue the parties choose |
| Venue envelopes | Internet Court (5,000-char slot) · Kleros ERC-1497 · UMA · generic |
| Evidence packs | format=art50 · format=safr (beta) |
| Idempotency | In-memory + Cloudflare D1 stores |
tersign intercept | Audit capture at the MCP boundary — a signed, digest-only action record per tool call (experimental) |
tersign interceptAn agent's tool calls are usually recorded, if at all, inside the agent's own code. Record them at the wire instead:
npx tersign intercept -- npx your-mcp-server
The proxy is a pure observer: bytes reach the server and the client exactly as sent, in order, unmodified. It runs on your side with your key, so each record is still your own report. Every tools/call that gets a response becomes an ActionRecordV1 signed by *your* key and, when a ledger is configured, counter-signed into a hash chain; a call cancelled or never answered leaves no record. Digests only: each record carries a digest of the call's arguments and one of its result or error (canonical JSON), never the content. Records go to a configured ledger, and fall back to a local ~/.tersign/intercepts- .jsonl, where they carry your signature only, so evidence is never silently dropped.
Experimental, and deliberately unopinionated about where the protocol lands: it implements the observation semantics of the audit-mode validator described in MCP SEP-2624 (Draft) as a transport-level proxy today, and is structured to move onto the interceptor primitive if and when that stabilizes. It makes no conformance claim to that draft.
npx tersign starts the MCP server (stdio). Official registry entry: io.github.tersignhq/evidence (active).
{
"mcpServers": { "tersign": { "command": "npx", "args": ["tersign"] } } }
No configuration is needed. With `TERSI
앞부분만 보여 드려요. 나머지는 저장소에서 읽어 보세요