Read-only MCP server: verify credentials and browse escrows on the Stellar testnet contract.
io.github.Iron-Mark/stellaroid-earn MCP Server
A read-only MCP server that verifies credentials and browses escrows on the Stellar testnet contract. It is designed for developers who need programmatic access to Stellar testnet escrow data and credential verification without modifying on-chain state.
🛠️ Key Features
Read-only MCP server
Verify credentials
Browse escrows on the Stellar testnet contract
🚀 Use Cases
Credential verification workflows for Stellar testnet escrow access
Inspecting escrow details from the Stellar testnet contract
⚡ Developer Benefits
Prevents state changes via read-only operation
Focused functions for credential checking and escrow browsing on the Stellar testnet
⚠️ Limitations
Read-only access (cannot perform write or transactional operations)
Verify a Stellaroid Earn credential by its SHA-256 certificate hash. Returns the on-chain status (issued/verified/revoked/suspended/expired), issuer, timestamps, and public audit links. Runs on Stellar testnet.
Look up an issuer in the Stellaroid Earn on-chain trust registry by Stellar address. Returns approval status (pending/approved/suspended), name, category, and website.
List escrowed paid trials (opportunities) on the Stellaroid Earn contract, newest first. Each ties an employer's escrowed XLM to a candidate's verified credential and moves draft -> funded -> submitted -> released/refunded.
Decoded recent contract events (credential registrations/verifications, escrow lifecycle, payments) from the Stellaroid Earn contract, deduplicated across Soroban RPC and the Stellar Expert indexer.
Deployed WASM hash 1b7479f1ca0f12846bbfdd8f0681670692e29e1f20618150912f010b7caf4b9f. Rebuilding the v3.0.0 release tag reproduces it byte for byte, and the deployed bytecode records its own build toolchain (rsver 1.95.0, rssdkver 26.1.0, cliver 27.0.0) so you can check it without trusting this README. Verified weekly by contract-verification.yml. Runbook: docs/operations/contract-verification.md.
stellaroid.tech always serves the latest production build (main). The April source lives on the april-bootcamp-and-monthly-builder branch; June and July on june-monthly-builder and july-monthly-builder.
July v3.2 product surface
Wallet-less guided demo - /demo: the full register → verify → escrow → payout story on real seeded testnet data (a released 25 XLM escrow and a live funded one), with per-step stellar.expert audit links. No wallet, no extension, works on a phone.
Opportunity directory - /opportunity: every live escrowed paid trial on the contract, with wallet-scoped filters (for you / created by you) and deep links into the milestone console.
Live escrow evidence - the status page and activity feeds now decode all escrow events (create/fund/submit/approve/release/refund) alongside credential events, deduplicated across the RPC and the Stellar Expert indexer; /app shows the events involving your connected wallet.
On-site pilot intake - /pilot has a real lead-capture form (rate-limited, honeypot-guarded, delivered by email) instead of a link-out, plus /contact, an honest privacy & terms page, and an RFC 9116 security.txt.
Performance pass - the multi-megabyte stellar-sdk is lazy-loaded out of every route's First Load JS (/app dropped 483 → ~260 KB gzipped), the brand typefaces (Orbitron/Exo 2) are self-hosted via next/font, and first-party client-error telemetry reports runtime failures to server logs with no third-party service.
Installable PWA - manifest with maskable icons, service worker (network-first pages, offline fallback, per-deploy cache versioning; verification pages are never served from cache), iOS splash screens. Add it to a phone home screen from the live site.
Mobile-first redesign - app-style bottom navigation with a More sheet, auto-hiding header, bottom-sheet dialogs, full safe-area/notch handling.
Multi-wallet signing - Freighter and Albedo natively, WalletConnect for mobile wallets (LOBSTR, xBull, Hana, Freighter mobile), and on desktop xBull, Rabet, LOBSTR, Hana, Klever, and Bitget via Stellar Wallets Kit - all behind one provider interface, lazy-loaded on first use. WalletConnect activates when a Reown project id is configured.
The public entry flow is organized around three personas: Issue, Verify, and Hire. Verified proof pages now hand employers into /employer with the proof hash and candidate wallet preloaded, then require a review checklist before escrow creation. They also hand recruiters into /talent/<address>?proof=<hash> so the candidate passport can show a known proof without pretending wallet-wide credential discovery exists yet. Issuer registration now explains approval readiness before signing, and /pilot keeps the first rollout bounded to a small testnet issuer pilot. Employer proof packs include a recruiter-safe summary plus an unsigned standards-alignment preview for W3C VC 2.0 and Open Badges 3.0 mapping. That preview is not a signed standards credential yet.
30-Second Pitch
Problem: Bootcamp certificates are PDFs that anyone can fake and no one can independently verify. Employers skip verification or pay for a background check service.
Solution: Stellaroid Earn anchors credential hashes on a Soroban smart contract where approved issuers register and verify certificates, anyone checks proof at a public URL with no login, and employers pay graduates in XLM on Stellar testnet, all on-chain.
Why Stellar: Sub-cent fees and 5-second finality make issuing credentials cheap enough that skipping it makes no sense. simulateTransaction lets anyone verify with zero wallet setup. Native XLM via SAC closes the loop from proof to payout on one chain.
Feature Gallery
Discover - Landing page with 3-step how-it-works flow
Verify - On-chain credential with green Verified badge
Issue & Pay - Dual-role dashboard for issuers and employers
Share - QR-scannable proof card on any mobile browser
Live Trust Artifact
Every credential produces a public Verified Badge URL - no wallet, no login, no API key. Green means verified on-chain. Amber means issued but not yet verified.
Two read paths: server-side RSC with revalidate=60 (CDN-cached proof pages) + client-side simulateTransaction (dashboard state)
One write path: Freighter signs → sendTransaction → poll for result
CSP locks connect-src to *.stellar.org and the WalletConnect relay - no other third-party origins
Contract Integration (Frontend to Soroban)
The frontend talks to the deployed stellaroid_earn contract with @stellar/stellar-sdk. The client lives in frontend/src/lib/contract-client.ts (writes + client-side reads) and frontend/src/lib/contract-read-server.ts (server-rendered proof pages). The SDK is lazy-loaded so its multi-megabyte bundle stays out of every route's first load.
ts
// frontend/src/lib/contract-client.tsimporttype * asStellarSdkfrom"@stellar/stellar-sdk";
// Lazy-load the SDK once, on the first contract read or wallet action.constgetSdk = () => import("@stellar/stellar-sdk");
// READ (no wallet): simulate an invocation against Soroban RPC.const server = new sdk.rpc.Server(appConfig.rpcUrl);
const sim = await server.simulateTransaction(tx);
const value = sdk.scValToNative(sim.result.retval);
// WRITE: build with TransactionBuilder, wallet signs, submit + poll.const tx = new sdk.TransactionBuilder(account, {
fee: sdk.BASE_FEE,
networkPassphrase: getExpectedNetworkPassphrase(),
})
.addOperation(
sdk.Operation.invokeContractFunction({
contract: appConfig.contractId, // NEXT_PUBLIC_SOROBAN_CONTRACT_IDfunction: method, // e.g. "verify_certificate"
args, // sdk.nativeToScVal(...) per argument
}),
)
.setTimeout(30)
.build();
const signedXdr = await wallet.sign(tx.toXDR()); // Freighter / Albedo / Stellar Wallets Kitconst sent = await server.sendTransaction(sdk.TransactionBuilder.fromXDR(signedXdr, passphrase));
const result = await server.pollTransaction(sent.hash);
Every public contract function has a matching typed wrapper in the client. The wrapper passes the exact contract function name to Operation.invokeContractFunction:
Contract function (contracts/stellaroid_earn/src/lib.rs)
Frontend wrapper (contract-client.ts)
register_issuer
registerIssuer()
approve_issuer
approveIssuer()
suspend_issuer
suspendIssuer()
get_issuer
getIssuer() (read / simulateTransaction)
register_certificate
registerCertificate()
verify_certificate
verifyCertificate()
get_certificate
getCertificate() (read / simulateTransaction)
revoke_certificate
revokeCertificate()
suspend_certificate
suspendCertificate()
reward_student
rewardStudent()
link_payment
linkPayment()
create_opportunity
createOpportunity()
fund_opportunity
fundOpportunity()
submit_milestone
submitMilestone()
approve_milestone
approveMilestone()
release_payment
releasePayment()
refund_opportunity
refundOpportunity()
get_opportunity
getOpportunity() (read / simulateTransaction)
The network passphrase in NEXT_PUBLIC_STELLAR_NETWORK_PASSPHRASE must match the network the contract is deployed on (testnet), or the wallet rejects the signature.
cd contracts/stellaroid_earn
make test# cargo test (contract suite)
make build # builds wasm32v1-none target# Deploy to testnet
stellar keys generate my-key --network testnet --fund
stellar contract deploy \
--wasm target/wasm32v1-none/release/stellaroid_earn.wasm \
--source my-key --network testnet
CI runs the contract gate with cargo test -p stellaroid_earn --locked and cargo build -p stellaroid_earn --target wasm32v1-none --release --locked in Contract CI.
Frontend
bash
cd frontend
cp .env.example .env.local # fill in contract ID + read address
npm install
npm run dev # http://localhost:3000
Open a paid-trial escrow against a verified credential
fund_opportunity(employer, opp_id)
Employer
Escrow the full trial amount into the contract
submit_milestone(candidate, opp_id)
Candidate
Mark the next milestone as delivered
approve_milestone(employer, opp_id)
Employer
Approve the submitted milestone
release_payment(employer, opp_id)
Employer
Release the approved milestone share to the candidate
refund_opportunity(employer, opp_id)
Employer
Return remaining escrowed funds to the employer
get_opportunity(opp_id)
Anyone
Read a paid-trial opportunity record
Credential Status Lifecycle
code
Issued --> Verified (issuer or admin calls verify_certificate)
--> Revoked (issuer or admin calls revoke_certificate)
--> Suspended (issuer or admin calls suspend_certificate)
--> Expired (reserved status; new credentials currently use expires_at = 0 unless a future issuer flow sets expiry)
Tests
Contract tests cover the trust layer, access control, revocation, opportunity escrow, milestone caps, and events:
code
running 12 tests
test test::t1_happy_path_with_approved_issuer ... ok
test test::t2_unapproved_issuer_cannot_issue ... ok
test test::t3_suspended_issuer_cannot_issue ... ok
test test::t4_wrong_approved_issuer_cannot_verify ... ok
test test::t5_revoked_credential_blocks_payment ... ok
test test::t6_issuer_events_emit ... ok
test result: ok. 12 passed; 0 failed; 0 ignored
Stellaroid Earn keeps fee bump transaction support (CAP-0015) behind a server-to-server authorization boundary. Public browser clients do not automatically send signed XDR to /api/fee-bump.
How it works:
A trusted server obtains a user-signed transaction for an allowed Stellaroid Earn method
The trusted server calls /api/fee-bump with Authorization: Bearer <FEE_SPONSOR_TOKEN>
The route enforces XDR size, signature, operation count, network, contract ID, method allow-list, and fee-ceiling checks
Only then does the sponsor key wrap the transaction as a fee bump
Config: FEE_SPONSOR_SECRET + FEE_SPONSOR_TOKEN are server-only. Public browser auto-sponsorship stays disabled; trusted server callers must provide the bearer token explicitly.
Browser fallback: normal user-paid Freighter transactions remain the default path.
Metrics & Monitoring
Status metrics:/status#metrics - public contract-event evidence, proof hashes, reward/payment events, and source labels on the operational status page
Health endpoint:/api/health - cached JSON health check (config, RPC latency, contract availability)
Events API:/api/events - structured contract event data for external consumers
Events stream:/api/events/stream - short-lived Server-Sent Events stream for live demo refreshes without adding a database
MCP server:/api/mcp - read-only remote Model Context Protocol endpoint (Streamable HTTP, no auth) so AI agents can verify credentials, inspect issuers, and browse escrowed paid trials; built on Vercel's mcp-handler + the official MCP TypeScript SDK
Vercel Analytics: Page analytics plus privacy-safe custom events for proof sharing, proof-pack downloads, employer handoff, shortlist saves, and escrow-start actions
Data Indexing
Contract events are read from two public sources. The app first queries Soroban RPC getEvents for recent contract events, then supplements that result with Stellar Expert's public contract event index so older testnet activity does not disappear from the demo surface when the RPC retention window moves on. Events are decoded from ScVal/XDR where possible, categorized by kind (cert_reg, cert_ver, reward, payment), deduplicated, source-labelled, and served through /api/events, /api/events/stream, plus /status#metrics.
This remains a lightweight serverless evidence layer, not a full analytics warehouse. Vercel page analytics and custom events help inspect proof/share/employer flow interest without storing raw wallet addresses or proof hashes; durable proof history, issuer conversion, and long-term product analytics still require a first-party read model.
Stellaroid Earn has 54 of the targeted 50 documented testnet wallet accounts with public network activity. That total is two groups: 30 independent participant wallets from the testnet review, plus 24 controlled QA accounts that I operate myself for structured product verification. Both groups are listed in full below and every wallet and transaction links to Stellar Expert.
The 24 QA accounts are disclosed as QA personas, not as independent people. So the figure above is wallet-account coverage with real network activity. It is not a claim of 54 separate users, and the independent participant count remains 30.
Testnet Wallet Evidence
30 independent participant wallet addresses from the Stellar testnet review are listed for public review. Each wallet address is verifiable on Stellar Expert. Some wallets have direct contract interactions such as register_issuer; others are funded participant wallets used during the review flow. The committed feedback snapshot keeps participant names and emails redacted.
View all 30 independent participant wallet addresses
The 24 QA account addresses that complete the 54-account total are listed separately in the guided QA evidence log, so each group stays checkable on its own.
Alongside the independent participant review, 24 controlled QA user accounts completed eight structured issuer, candidate, and employer journeys on the public testnet contract. The run produced 64 QA-account-signed transactions plus eight facilitator approvals, including eight verified credentials and eight released 1 XLM paid opportunities.
The guided QA evidence log links every public account and transaction. The organization, credential, cohort, and opportunity names are fictional scenario data. The guided QA accounts are included in the 54-account testnet coverage total and identified by their QA purpose in the evidence log.