# Coding agents and IDEs

Coding agents and IDEs such as Claude Code, Cursor and Goose call tools over the Model Context Protocol (MCP). `tnsai-mcp` serves TnsAI tools to them, generates a Goose extension manifest, and reads Goose extensions and recipes. For the other direction, where a TnsAI agent calls an MCP server, see [MCP client](../mcp/client.md).

## Example

<!-- java-contract: src/main/java/com/example/tnsai/docs/ConnectCodingAgentsExample.java -->
```java
package com.example.tnsai.docs;

import com.tnsai.enums.BuiltInTool;
import com.tnsai.mcp.client.McpClient;
import com.tnsai.mcp.goose.GooseExtensionLoader;
import com.tnsai.mcp.goose.GooseRecipeParser;
import com.tnsai.mcp.goose.TnsAIGooseExtension;
import com.tnsai.mcp.registry.McpServerEntry;
import com.tnsai.mcp.server.HttpMcpServer;
import com.tnsai.mcp.server.TnsAIToolProvider;
import com.tnsai.tools.method.ToolMethod;
import com.tnsai.tools.method.ToolMethodRegistry;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/** Compilation contract for connect/coding-agents.md. */
public final class ConnectCodingAgentsExample {

    private ConnectCodingAgentsExample() {
    }

    static HttpMcpServer serveToolkits(Object... ownTools) throws IOException {
        HttpMcpServer server = HttpMcpServer.builder()
            .port(3000)                                   // the default, 0, picks a free port
            .serverName("tnsai")
            .addToolProvider(TnsAIToolProvider.fromPojos(
                BuiltInTool.WEB_SEARCH_TOOLS.instantiate(),   // needs tnsai-tools on the classpath
                BuiltInTool.PDF_TOOLS.instantiate()))
            .addToolProvider(TnsAIToolProvider.fromPojos(ownTools))
            .build();
        server.start();                                   // serves http://localhost:3000/mcp
        return server;
    }

    static void printSchemas(Object... toolPojos) {
        for (ToolMethod tool : new ToolMethodRegistry(List.of(toolPojos)).all()) {
            System.out.println(tool.name() + ": " + tool.parametersSchema());
        }
    }

    static String gooseManifest(McpClient connectedClient) throws IOException {
        // The client must already be connected and initialized.
        return TnsAIGooseExtension.toJson(TnsAIGooseExtension.generateManifest(connectedClient));
    }

    static List<McpServerEntry> gooseExtensions(Path extensionDir) throws IOException {
        GooseExtensionLoader loader = new GooseExtensionLoader();
        return loader.loadFromDirectory(extensionDir).stream()   // unreadable files are skipped
            .map(loader::toServerEntry)                           // empty unless type is "mcp"
            .flatMap(Optional::stream)
            .toList();
    }

    static List<Map<String, Object>> recipeCalls(String recipeJson) throws IOException {
        GooseRecipeParser.Recipe recipe = GooseRecipeParser.parse(recipeJson);
        return GooseRecipeParser.toMcpCalls(recipe);      // {"name": ..., "arguments": ...} per step
    }
}
```

## Serve TnsAI tools

`TnsAIToolProvider.fromPojos(...)` turns every `@Tool` method on the objects you pass into an MCP tool. Built-in toolkits come from `BuiltInTool.X.instantiate()`. It loads the class by name, so `tnsai-tools` must be on the classpath. Without it, `instantiate()` throws `BuiltInToolInstantiationException`. Expose the toolkits the client needs, not the whole catalog. When two providers list the same tool name, `tools/list` shows it twice and calls go to the provider added last, so keep names unique.

`HttpMcpServer` listens on a free port unless you set `port`, so set it when a client config names a fixed URL. The endpoint is `http://localhost:<port>/mcp`. [HTTP server](../mcp/server.md#http-server) lists the builder options.

`HttpMcpServer` checks no credentials. Keep it on the local machine, or put it behind a proxy that authenticates callers and terminates TLS.

## Connect a client

Claude Code adds an HTTP MCP server with its CLI:

```bash
claude mcp add --transport http tnsai http://localhost:3000/mcp
```

Cursor, Continue and other MCP clients take the same URL in their MCP server settings. A client that starts servers as subprocesses needs a stdio server instead. [Stdio server](../mcp/server.md#stdio-server) shows one.

## Inspect tool schemas

`new ToolMethodRegistry(List.of(pojos...)).all()` returns each tool's name, description and JSON Schema for its parameters (`parametersSchema()`). An agent builds the same registry type from its tool objects, so the schemas match what the agent sends to its model. The constructor throws `IllegalArgumentException` when two tools share a name. No agent is needed.

## Goose

| Class | Does |
|---|---|
| `TnsAIGooseExtension` | `generateManifest(client)` lists the tools of a connected, initialized MCP client and returns a manifest. Its name and version come from the server's `initialize` reply, or `tnsai` and `1.0.0` when the server sent none. `toJson(manifest)` writes indented JSON. |
| `GooseExtensionLoader` | `loadFromDirectory(dir)` reads every `*.json` file in the directory. It logs and skips files it cannot parse, and throws `IOException` when `dir` is not a directory. `toServerEntry(extension)` returns an `McpServerEntry` for extensions of type `mcp` (the default) and empty for any other type. The transport defaults to `stdio`, and the endpoint comes from `endpoint`, then `command`. |
| `GooseRecipeParser` | `parse(json)` reads `name`, `description` and `steps`, where each step has `tool`, `params` and an optional `output`. `toMcpCalls(recipe)` returns one `{"name", "arguments"}` map per step. |

`toMcpCalls` copies `params` as they are. It does not run the steps or fill in `{{variable}}` placeholders from an earlier step's `output`, so your code does that between calls.

[MCP registry](../mcp/registry.md) covers `McpServerEntry`.

## llms.txt and AGENTS.md

Two plain Markdown files help coding agents work with a project built on TnsAI:

- `/llms.txt` at a site root lists what the project is and where its docs live. [tnsai.dev/llms.txt](https://tnsai.dev/llms.txt) is one example, and [llmstxt.org](https://llmstxt.org) describes the format.
- `AGENTS.md` at a repository root gives coding agents their working instructions. [agents.md](https://agents.md) describes the convention.

## Related

- [MCP server](../mcp/server.md)
- [MCP client](../mcp/client.md)
- [MCP transports](../mcp/transports.md)
- [Tool catalog](../tools/catalog.md)
- [SCOP](scop.md)
