# Surface Contract: how platform APIs really behave

> Evidence-cited machine-readable contracts for how agent platform APIs really behave

- name: dev.workers.penny-mcamp.penny-surface-contract/surface-contract
- version: 2026.10.13
- connection class: R0 (autonomous)
- trust: 82/100 flags: no-repository
- quality: 73/100 (new)
- owner: not claimed
- descriptor: https://api.protogrid.dev/v1/servers/dev.workers.penny-mcamp.penny-surface-contract%2Fsurface-contract
- tools: https://api.protogrid.dev/v1/servers/dev.workers.penny-mcamp.penny-surface-contract%2Fsurface-contract/tools

**An agent can connect right now, no human step.** Remote endpoint, no authentication, reachable on the last probe.

## Connection (mcpServers)

```json
{
  "mcpServers": {
    "surface-contract": {
      "type": "http",
      "url": "https://penny-surface-contract.penny-mcamp.workers.dev/mcp"
    }
  }
}
```


## Trust

- hygiene: 80
- liveness: 99
- freshness: 100
- provenance: 55
- drivers: +dns-namespace +website +reachable +uptime-96% +updated-7d-ago -no-repository
- Derived from observable signals (official registry feed and our own credential-free probes); no code audit performed.

## Quality 73/100 (new)

### protocol: 75 (weight 25)

- warn `protocol.modern`: newest supported version is 2025-06-18; 2026-07-28 not supported, older versions are deprecated until 2027-07-28
- n/a `protocol.stateless`: only applies to 2026-07-28 servers
- pass `protocol.transport`: streamable HTTP
- n/a `protocol.list_ttl`: only applies to 2026-07-28 servers

### authorization: n/a (weight 15)

- n/a `auth.prm`, `auth.as_metadata`, `auth.cimd`: no remote uses OAuth
- n/a `auth.secret_in_url`: no templated URL

### tool hygiene: 71 (weight 30)

- pass `tools.descriptions`: every tool has a description
- pass `tools.description_length`: descriptions are concise
- pass `tools.schemas`: every tool has an object input schema
- fail `tools.annotations`: no tool declares readOnlyHint or destructiveHint, so clients cannot tell safe calls from risky ones
- fail `tools.directory_hints`: no tool declares all four of readOnlyHint, destructiveHint, idempotentHint and openWorldHint; missing: get_surface_contract (readOnlyHint, destructiveHint, idempotentHint, openWorldHint); prepay_check (readOnlyHint, destructiveHint, idempotentHint, openWorldHint); verify_surface (readOnlyHint, destructiveHint, idempotentHint, openWorldHint); …
- pass `tools.token_cost`: about 1,288 tokens to load every tool
- pass `tools.api_dump`: tools are not a one-to-one API dump

### stability: n/a (weight 15)

- n/a `stability.changes`, `stability.rug_pull`: tool history recorded for 6 of the 7 days needed

### dependencies: n/a (weight 15)

- n/a `deps.known_vulns`, `deps.mcp_sdk_version`, `deps.resolvable`: no npm or PyPI package

- tools: 7, about 1,288 tokens to load them all
- tool set hash: 51e8216003cb316a1c9bd874a65b0e66
- tools last changed: 2026-10-15T13:13:49.386Z
- badge: [![protogrid quality](https://protogrid.dev/badge/dev.workers.penny-mcamp.penny-surface-contract/surface-contract.svg)](https://protogrid.dev/servers/dev.workers.penny-mcamp.penny-surface-contract/surface-contract)
- Checks run on what our credential-free, read-only probes observe; tools are never called and no code audit is performed.

### Tool changes

- 2026-10-15 `prepay_check` added
  - Check an x402 route BEFORE you pay it. GET /v1/prepay?url=<the route> makes ONE unpaid GET with no payment header and no credential, and returns one row: the measured HTTP status, the parsed x402 v2 challenge (scheme / network / asset / amount / payTo), whether that challenge is schema-valid exact-on-Base, and whether its payTo and price agree with the seller's own card (pass `card` to read that card with one more unpaid GET). No payment is made, no credential is sent, no redirect is followed, and a transport failure on our side is reported as unknown rather than as a fact about the seller. Use it to gate a payment decision on measured terms instead of on a seller's prose.
- 2026-10-15 `contribute_discrepancy` changed (description, inputSchema) **meaning changed**
  - before: Report a platform behaviour that contradicts a published claim, or a new claim, with evidence. Stored as pending; a published contract is never changed without independent verification.
  - after: Report a platform behaviour that contradicts a published claim, or a new claim, with evidence. One-line call: POST /v1/contribute with {contractId, kind, statement, evidence[], reporter, observedAt}. Stored as pending; a published contract is never changed without independent verification. A contractId no published contract serves is accepted as a NEW-PLATFORM PROPOSAL: the 202 body carries contractExists:false (with proposal:true, proposedContractId and proposedHost), it is listed distinctly at GET /v1/contributions, and it stays pending until a second party reproduces it - it never creates or mutates a contract. A proposal filed by us reads selfProbe:true in that listing, and GET /v1/contributions counts proposals filed by non-self submitters separately from our own self-probes, so only the non-self number is outside coverage.
- 2026-10-15 `preflight_mcp_server` added
  - Run the anonymous MCP handshake against ANY https MCP endpoint you name, right now, and get back a verdict (open / refused / unreachable / initialize-transport-error), the shape of any refusal body, whether the server is stateful (sets Mcp-Session-Id), how many tools tools/list returns, and the guard clauses that follow. Use it before wiring an MCP server into your own config. Pass `urls` (up to 5) to check a whole mcp.json in one call. When the endpoint refuses, it also reports whether the refusal advertises a credential path (an RFC 9728 resource_metadata pointer) and whether that pointer resolves to a metadata document naming an authorization server, so you learn where a token would come from without writing that parsing yourself. No credential is sent, none is obtained, and none of their tools is ever called.

Full history: https://api.protogrid.dev/v1/servers/dev.workers.penny-mcamp.penny-surface-contract%2Fsurface-contract/changes

## Remotes

- https://penny-surface-contract.penny-mcamp.workers.dev/mcp (streamable-http, auth none, reachable true, uptime30d 0.962963)

## Packages

_none_

## Tools (7)

- `contribute_discrepancy`: Report a platform behaviour that contradicts a published claim, or a new claim, with evidence. One-line call: POST /v1/contribute with {contractId, kind, statement, evidence[], reporter, observedAt}. Stored as pending; a published contract is never changed without independent verification. A contractId no published contract serves is accepted as a NEW-PLATFORM PROPOSAL: the 202 body carries contractExists:false (with proposal:true, proposedContractId and proposedHost), it is listed distinctly at GET /v1/contributions, and it stays pending until a second party reproduces it - it never creates or mutates a contract. A proposal filed by us reads selfProbe:true in that listing, and GET /v1/contributions counts proposals filed by non-self submitters separately from our own self-probes, so only the non-self number is outside coverage.
- `get_integration_recipe`: Get a plain-text integration recipe for a platform: the order of operations to use it, and a guard clause for every behaviour we measured going wrong, each naming the contract claim behind it. Derived from the contract, so it cannot drift from it.
- `get_surface_contract`: Get the machine-readable surface contract for a platform host (read/write semantics, pending states, rate limits, limits, idempotency, pagination completeness, data portability), each claim carrying its evidence and its verification status.
- `list_surface_contracts`: List the platform surface contracts published in Penny's free registry, with claim counts.
- `preflight_mcp_server`: Run the anonymous MCP handshake against ANY https MCP endpoint you name, right now, and get back a verdict (open / refused / unreachable / initialize-transport-error), the shape of any refusal body, whether the server is stateful (sets Mcp-Session-Id), how many tools tools/list returns, and the guard clauses that follow. Use it before wiring an MCP server into your own config. Pass `urls` (up to 5) to check a whole mcp.json in one call. When the endpoint refuses, it also reports whether the refusal advertises a credential path (an RFC 9728 resource_metadata pointer) and whether that pointer resolves to a metadata document naming an authorization server, so you learn where a token would come from without writing that parsing yourself. No credential is sent, none is obtained, and none of their tools is ever called.
- `prepay_check`: Check an x402 route BEFORE you pay it. GET /v1/prepay?url=<the route> makes ONE unpaid GET with no payment header and no credential, and returns one row: the measured HTTP status, the parsed x402 v2 challenge (scheme / network / asset / amount / payTo), whether that challenge is schema-valid exact-on-Base, and whether its payTo and price agree with the seller's own card (pass `card` to read that card with one more unpaid GET). No payment is made, no credential is sent, no redirect is followed, and a transport failure on our side is reported as unknown rather than as a fact about the seller. Use it to gate a payment decision on measured terms instead of on a seller's prose.
- `verify_surface`: Run the anonymous conformance checks for a contract now and return verified / failed / unknown / manual / unsupported per claim.
