MCP in your app

@valv/mcp-sdk turns a valv instance you configure into an MCP server, with the policy and per-request context in your hands. Use it when your app exposes its own data to a coding agent and you need each request scoped to a real user or tenant, not a fixed connection.

This is the difference from the zero-config server: there you point at a connection string and set a fixed context; here you own the valv instance and resolve identity per request.

Serve over stdio

Configure valv as you would in any app, then start a stdio server. The context resolver runs per request, so each call carries the right identity:

import { createValv } from "@valv/prisma"
import { startStdioServer } from "@valv/mcp-sdk"

const valv = await createValv(prisma, { defaultPolicy: "deny-all" })

valv.policy("orders", (ctx) => ({ read: { tenant_id: ctx.tenant.id } }))

await startStdioServer(valv, {
  context: () => resolveIdentity(), // resolved per request from env, headers, etc.
})

Serve over HTTP

To serve the same tools over Streamable HTTP, use startHttpServer. This suits a remote agent connecting to your service rather than a local process:

import { startHttpServer } from "@valv/mcp-sdk"

await startHttpServer(valv, {
  context: (request) => resolveIdentity(request), // derive identity from the request
})

Building the server yourself

createMcpServer returns the underlying MCP server without starting a transport, so you can mount it inside an existing server or wire a custom transport:

import { createMcpServer } from "@valv/mcp-sdk"

const server = createMcpServer(valv, { context: (request) => resolveIdentity(request) })

Because the context resolver runs per request, the same enforcement you write for your app applies to the agent: a request only ever sees the rows and columns its identity allows.

Next steps

  • Policies: scope each request by user or tenant.
  • MCP server: the zero-config option for local coding agents.