Quick Start
Executive Summary
Add pascal-mcp-sdk to your project (lwpt add or vendor seven
files), register tools with a name, description, schema, and a
handler function, and call RunMCPStdioServer — or serve the same
registrations over Streamable HTTP with TMCPHTTPServer. Wire the
binary into any MCP client.
This page is for consumers of the library. Building and testing the library itself is covered in CONTRIBUTING.md.
Prerequisites
- FPC 3.2.2 —
apt install fpc/brew install fpc/ the win32+win64 combo installer from freepascal.org. - lwpt (optional — for the dependency path) —
brew install frostney/tap/lwpt, or download the release tarball for your platform from lwpt's releases, verify it against the release's checksums file, and putlwpton PATH.
Get the library
As an lwpt dependency, from your project root:
lwpt add frostney/pascal-mcp-sdk@^2.0
lwpt buildYour program's uses MCP.Server resolves through the nested manifest;
the library's *.Test.pas files do not leak into your lwpt test
discovery.
Without lwpt, vendor the seven files —
source/units/MCP.JSONRPC.pas, MCP.Protocol.pas, MCP.Schema.pas,
MCP.Server.pas, MCP.Transport.Stdio.pas, MCP.Transport.HTTP.pas,
Shared.inc — into your unit path and compile with
-Fu<that-path> -Fi<that-path>.
Write your own server
program myserver;
{$mode delphi} {$H+}
uses
fpjson,
MCP.Protocol, MCP.Schema, MCP.Server, MCP.Transport.Stdio;
function Greet(AArguments: TJSONObject;
const ACtx: TMCPRequestContext): TMCPToolResult;
begin
Result := MCPTextResult('Hello, ' + AArguments.Get('name', 'world') + '!');
end;
var
Server: TMCPServer;
begin
Server := TMCPServer.Create('my-server', '1.0.0');
try
Server.Instructions := 'Greets people.'; // surfaced via server/discover
Server.RegisterTool('greet', 'Greet someone by name',
ObjectSchema.AddString('name', 'Who to greet'),
Greet);
Server.RegisterTextResource('mcp://my-server/motd', 'motd',
'text/plain', 'Be excellent to each other.');
RunMCPStdioServer(Server);
finally
Server.Free;
end;
end.Prefer typed arguments? Declare a TMCPArgs descendant and register
the class — it expands into the schema, and your handler receives a
populated, validated instance. See
Schemas for the full model and
the cookbook for the worked add tool.
Key behaviours you get for free:
- Argument validation before your handler runs: raw-handler tools
are checked against their registered schema's subset (required,
types, enums, defaults) and typed tools against their class —
violations become in-band
isErrorresults a model can correct against. - Validation errors (
-32602), version negotiation (-32022with the supported list), and method-not-found (-32601) are produced by the library; handlers never see malformed metadata. - Handler exceptions become
isError: truetool results — the in-band error channel models can self-correct against. resultTypeandserverInfoare stamped on every result.- Today's clients work out of the box: the server is dual-era by
default, so a client opening with the classic
initializehandshake — which current releases of Claude Code, Claude Desktop, and Codex all still speak (see Your first conversation) — is served that era faithfully, while stateless 2026-07-28_metarequests are served natively — same registries, same handlers. SetServer.DualEra := Falsefor a strict modern-only server that rejectsinitializenaming its supported versions. - Mid-call input (MRTR): return
MCPInputRequired(...)from a tool handler — orMCPPromptInputRequired(...)from a prompt result handler — to ask the client for more input (elicitation form/url, sampling, roots); the client retries the call and your handler re-enters with the responses onACtx— see Tools and the worked example in the cookbook.
These protocol behaviours — MRTR, Streamable HTTP/SSE, the per-request
_metamodel, and the EOF shutdown contract — implement spec revision 2026-07-28. The dated official-spec citations (modelcontextprotocol.io) live in architecture.md's Spec grounding section.
Serve over Streamable HTTP
The same server object serves HTTP with a transport swap (modern era
only — HTTP clients speak 2026-07-28; the binding validates the
mirrored Mcp-* headers, streams SSE for requests that opt into
progress/log notifications, and binds 127.0.0.1 by default):
uses
{$IFDEF UNIX} cthreads, {$ENDIF} // first in the program uses clause
..., MCP.Transport.HTTP;
Transport := TMCPHTTPServer.Create(Server);
Transport.Port := 3000; // POST http://127.0.0.1:3000/mcp
Transport.Run; // blocks; Transport.Stop unblocks itTry it: ./build/mcpdemo --http 3000.
Every HTTP request still carries _meta in its body, and the mirrored
Mcp-* headers are derived from it. The transport does not reject a
request that omits the header with a header error, but the core still
requires _meta and answers -32602 when it is missing — the header
tolerance is not a way to skip _meta.
Talk to a stdio server by hand
Every modern request carries the per-request _meta (this is the
stateless 2026-07-28 revision — there is no initialize handshake):
./build/mcpdemo <<'EOF'
{"jsonrpc":"2.0","id":1,"method":"server/discover","params":{"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}
{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"add","arguments":{"a":19,"b":23},"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}
EOFThe first line answers with supportedVersions, capabilities, and the
server's instructions; the second with content +
structuredContent: {"sum": 42}. Closing stdin (the heredoc ending)
makes the server exit — that is the spec's graceful-shutdown contract.
Register the server with an MCP client
Any client that launches stdio servers and speaks a supported protocol revision works, thanks to the dual-era default. With Claude Code it is one command:
claude mcp add my-server /absolute/path/to/myserver
claude mcp list # → my-server: … - ✔ ConnectedThe generic configuration shape:
{
"mcpServers": {
"my-server": {
"command": "/absolute/path/to/myserver"
}
}
}Logging goes to stderr only (MCPLogToStderr) — stdout belongs to
the protocol.
Next steps
- Tools — the full registration and validation model.
- Prompts and resources — the other two things a server exposes.
- Configuration — instructions, caching hints, error redaction, dual-era mode.
- Shipping your server — release builds and the runtime contract.
- Cookbook — every pattern above as a complete, runnable example.