A MCP server which connects to Siemens TIA Portal.
- TIA Portal Openness API Overview
- TIA Portal Openness API Documentation
- TIA Portal Openness API for automation of engineering workflows
- TIA Portal Openness API for automation of engineering workflows - Export/Import Documentation
- Connect to a TIA Portal instance
- Browse and interact with TIA Portal projects
- Perform basic project operations from within VS Code
- Read the full PLC software: program blocks, PLC data types, tags and constants, watch and force tables, external source files, and cross references
- Optionally create, rename, delete, move and import project objects (see Write mode)
| Argument | Description |
|---|---|
--tia-major-version <n> |
TIA Portal major version to bind against. Default 21. |
--project-path <file> |
Preset for the path argument of OpenProject / OpenTiaProject. See below. |
--software-path <path> |
Preset for the softwarePath tool argument, e.g. PLC_1. See below. |
--export-path <path> |
Preset for the exportPath tool argument. See below. |
--logging <1|2|3> |
1 stderr, 2 debug output, 3 Windows event log. Omit for no logging. |
--doctor |
Print the environment report and exit without starting the MCP server. |
--preserve-path |
Flag: preservePath defaults to true for the export tools. See below. |
--with-dependencies |
Flag: withDependencies defaults to true for the ExportSource* tools. See below. |
--force-presets |
Flag: the path, softwarePath and exportPath presets cannot be overridden. See below. |
--allow-write |
Register the project-mutating tools. Omitted by default; see below. |
softwarePath, exportPath, preservePath and withDependencies (the ExportSource* tools) appear in many tools, path (the project file) in
OpenProject and OpenTiaProject. Set them once in the args
of the MCP server entry in your client's JSON configuration and the model no longer has to pass them:
"args": ["--project-path", "D:\\Projects\\Plant\\Plant.ap21", "--software-path", "PLC_1", "--export-path", "D:\\Export", "--preserve-path", "--with-dependencies"]- A preset argument becomes optional in
tools/list; a tool call that omits it (or sendsnullor an empty string) uses the preset. A value passed in the call always overrides the preset. - Without a preset nothing changes: the argument stays required.
GetStatelists the active presets inPresets.- A single
--software-pathonly fits a project with one PLC; passsoftwarePathexplicitly otherwise. exportPath/importPathis the base directory shared by all PLCs. Every export and folder-based import works below<exportPath>/<softwarePath>/, e.g.D:\Export\Group1\PLC_1\Program blocks\...,...\PLC data types\...,...\PLC tags\...and...\Watch and force tables\...(the folder names of the project tree in the interface language of TIA Portal); each/insoftwarePathis a folder level. Imports that take the full path of a single file are unaffected.- Prompts (slash commands) use the presets too: an argument with a preset is optional in the prompt list and
is filled in when left out. Claude Code fills prompt arguments by position, so to override only
exportPathpasssoftwarePathas well. - With
--force-presetsthepath,softwarePathandexportPathpresets that are set become binding: they are removed fromtools/listand from the prompt arguments, and a call that still sends them is overwritten with the preset.preservePathandwithDependenciesstay overridable.OpenProjectcan then only open the preset project.GetStatelists them inForcedPresets. The option only fixes these arguments, it is not a sandbox: theimportPath/filePathof the import tools and the names insideblockPathare not restricted. In a slash command, type only the arguments that are still listed.
The server is read-only unless it is started with --allow-write.
- Without the flag the 51 project-mutating tools are not registered at all, so they never
appear in
tools/list. A model cannot call what it cannot see, and the tool list stays small. - With the flag they are registered and annotated
destructiveHint: true, so a client can still prompt before each call. GetStateand the--doctorreport both exposeAllowWrite, so a client can tell whether the tools are missing by configuration rather than by version.- Write operations change the project in memory only. Every write response says so and names
the tool that persists it:
SaveProject, orSaveSessionwhen a multiuser local session is open.
Export tools are intentionally not gated. ExportXmlBlock, ExportXmlTagTable, ExportXmlWatchTable
and friends only write files on the machine running the server; they never modify the project.
They are annotated destructiveHint: true because they can overwrite files on disk.
To enable write mode, add the argument to your client configuration, for example
"args": ["--allow-write"].
Read-only tools (69) are always available.
| Area | Tools |
|---|---|
| Portal and state | GetPortals, Connect, Disconnect, GetState, Doctor |
| Project and session | GetProject, OpenProject, SaveProject, SaveAsProject, CloseProject |
| Devices | GetProjectTree, GetDevices, GetDeviceInfo, GetDeviceItemInfo |
| PLC software | GetSoftwareInfo, GetSoftwareTree, CompilePlcSoftware, CompileCodeBlock, ExportOpcUaXml |
| Blocks | GetBlocks, GetBlockInfo, GetBlocksWithHierarchy, ExportXmlBlock, ExportXmlBlocks |
| Types | GetTypes, GetTypeInfo, ExportXmlType, ExportXmlTypes |
| Tags and constants | GetTagTables, GetTagTableInfo, GetTags, GetTagInfo, GetConstants, ExportXmlTagTable |
| Watch and force tables | GetWatchTables, GetWatchTableInfo, GetForceTables, ExportXmlWatchTable, ExportXmlForceTable |
| External sources | GetExternalSources, GetExternalSourceInfo, ExportSourceBlock, ExportSourceBlocks, ExportSourceType, ExportSourceTypes, ExportSources |
| Read source inline | GetXmlBlock, GetXmlType, GetSourceBlock, GetSourceType, GetDocumentsBlock, GetDocumentsType |
| Cross references | GetCrossReferences |
| Libraries | GetOpenLibraries, GetReferencedLibraries |
| Multiuser | GetMarkedObjects, CheckIsUpToDate |
| Block documents (V20+) | ExportAsDocuments, ExportBlocksAsDocuments |
| Type documents (V21+) | ExportTypeAsDocuments, ExportTypesAsDocuments |
| Understand and read (comfort) | GetPlcSummary, ResolveObjectPath, WhereUsed, FindInCode, GetBlockInterface, PreviewImport, OpenTiaProject, ExportPlcAsDocuments |
| Whole PLC program | ExportPlcProgram (format per object type from tia.json, see below), GetExportFormats |
Write tools (51) require --allow-write.
| Area | Tools |
|---|---|
| Block and type groups | CreateBlockGroup, DeleteBlockGroup, CreateTypeGroup, DeleteTypeGroup |
| Blocks and types | DeleteBlock, RenameBlock, DeleteType, RenameType, CreateFB, CreateInstanceDB |
| Copy and move | CopyBlock, MoveBlock, CopyType, MoveType |
| Tag tables | CreateTagTable, DeleteTagTable, RenameTagTable, CreateTagTableGroup, DeleteTagTableGroup, ImportXmlTagTable |
| Tags and constants | CreateTag, UpdateTag, DeleteTag, CreateUserConstant, UpdateUserConstant, DeleteUserConstant |
| Watch tables | CreateWatchTable, RenameWatchTable, DeleteWatchTable, CreateWatchTableGroup, DeleteWatchTableGroup, ImportWatchTable |
| External sources | CreateExternalSourceFromFile, DeleteExternalSource, CreateExternalSourceGroup, DeleteExternalSourceGroup, ImportExternalSource, ImportSourceBlock, ImportSourceType, ImportSourceBlocks, ImportSourceTypes, ImportSources |
| Type documents (V21+) | ImportTypeFromDocuments, ImportTypesFromDocuments |
| XML and documents | ImportXmlBlock, ImportXmlType, ImportFromDocuments (V20+), ImportBlocksFromDocuments (V20+) |
| Whole PLC program | OverwritePlcProgram, ImportPlcProgramChanges (sources and XML, preview by default, see below) |
| Multiuser | CommitChanges (commits the local session to the server and closes the session) |
GetSoftwareTree accepts a sections argument - any comma separated subset of
blocks,types,tags,watch,sources, default all - to keep the output small on a large PLC.
GetCrossReferences accepts maxDepth (1-3, default 1) for the same reason.
Paths used by these tools are root-relative: 1_Tests/FC_Block_1, not
Program blocks/1_Tests/FC_Block_1. Use GetProjectTree and GetSoftwareTree to discover them.
TIA Portal exports each kind of object in the format set under Options > Settings > Version control interface >
Export formats: SIMATIC SD documents (.s7dcl, .s7res), SimaticML (.xml) or a source file. Openness cannot
read that setting (the settings tree it offers has no export formats), so the server keeps the formats in a plain,
visible file at the root of the export folder:
<exportPath>/tia.json
It is one file for all PLCs below <exportPath>, because the setting is global. It is meant to be kept and committed
together with the export, so everyone who works with the folder uses the same formats.
You normally do not write it. The first time a tool needs it and it does not exist, the server creates it with the defaults TIA Portal offers for a new workspace:
{
"version control interface": {
"code blocks-LAD": "SIMATIC SD(.s7dcl, .s7res)",
"code blocks-FBD": "SIMATIC SD(.s7dcl, .s7res)",
"code blocks-SCL": "SIMATIC SD(.s7dcl, .s7res)",
"code blocks-STL": ".awl",
"data blocks": "SIMATIC SD(.s7dcl, .s7res)",
"safety data blocks (F-DBs)": "SIMATIC SD(.s7dcl, .s7res)",
"PLC data types": "SIMATIC SD(.s7dcl, .s7res)",
"F-compliant PLC data types (UDT)": "SIMATIC SD(.s7dcl, .s7res)"
}
}Available file formats per object type; the first one listed is the default of a new file:
| Key | Available formats |
|---|---|
code blocks-LAD |
SIMATIC SD(.s7dcl, .s7res), .xml |
code blocks-FBD |
SIMATIC SD(.s7dcl, .s7res), .xml |
code blocks-SCL |
SIMATIC SD(.s7dcl, .s7res), .scl, .xml |
code blocks-STL |
.awl, .xml |
data blocks |
SIMATIC SD(.s7dcl, .s7res), .db, .xml |
safety data blocks (F-DBs) |
SIMATIC SD(.s7dcl, .s7res), .xml |
PLC data types |
SIMATIC SD(.s7dcl, .s7res), .udt, .xml |
F-compliant PLC data types (UDT) |
SIMATIC SD(.s7dcl, .s7res), .xml |
Check a created file. The server cannot see your TIA Portal settings, so the defaults may differ from yours. The
response of ExportPlcProgram (Notes and the message) and of GetExportFormats (Created, Hint) says when the
file was just created and asks you to compare it with the dialog above. Correct it by hand if it differs. The file
only tells the server what to write; it does not change the setting in TIA Portal. An existing file is never
overwritten.
Each key names an object type, the value is the text TIA Portal shows for it:
| Value | Written as | Fits |
|---|---|---|
SIMATIC SD(.s7dcl, .s7res) |
documents, .s7dcl and .s7res (blocks V20+, types V21+) |
every block and PLC data type except STL blocks |
.xml |
SimaticML, .xml |
every block and PLC data type |
.awl, .scl, .db, .udt |
external source, the same extension | STL, SCL, data blocks, PLC data types (not LAD, FBD) |
| Key | Controls |
|---|---|
code blocks-LAD, -FBD, -SCL, -STL |
blocks of that language |
data blocks |
data blocks |
PLC data types |
PLC data types |
safety data blocks (F-DBs), F-compliant PLC data types (UDT) |
listed as TIA Portal shows them; not read separately yet |
Rules:
- Keys and values are not case sensitive. Other keys are kept and shown but have no effect, so a longer file from a copy does not break anything.
- If the file has no entry for an object type that occurs in the PLC, holds a value that is not one of the formats
above, or is not valid JSON,
ExportPlcProgramfails before it writes anything and names the file and the key. - A block of a language without an entry (GRAPH, for example) is skipped and listed in
Skipped. A source format for a block that has no source form (LAD as.awl) is skipped with a reason.
Who reads it: ExportPlcProgram decides the format of every object from it. GetExportFormats(exportPath) shows what
the file says and which export tool writes each format, so an agent can pick the right one. The narrow export tools
(ExportXmlBlock, ExportSourceBlock, ExportAsDocuments, ...) do what their name says and do not read it. The import
tools do not read it either.
These tools move all blocks and PLC data types of a PLC software in one call. ExportPlcProgram writes each
object in the format that tia.json gives for its object type; the file
is created with defaults when it is missing, so check it.
SIMATIC SD documents need a project that is prepared for that format: TIA Portal refuses an object with "needs
preparation for the format of Simatic SD" until you select it and run Tools > Prepare for Simatic SD. Openness
has no call for that step, so ExportPlcProgram cannot do it. Such an object is listed in Failures with the
message of TIA Portal, and the export goes on with the others; an export that finished with warnings is named in
Notes.
Blocks of a language that has no entry in the settings (GRAPH, for example) are skipped and listed in Skipped; use ExportXmlBlock
or ExportAsDocuments for them. OverwritePlcProgram and ImportPlcProgramChanges still import only sources and
XML, so the files of a SIMATIC SD folder are not imported by them.
- Layout:
<exportPath>/<softwarePath>/Program blocks/<groups>/and.../PLC data types/<groups>/, one file per object, always mirroring the project groups. It is the treeExportSourceswrites, so an XML file lies next to the sources of its group. ExportPlcProgram(softwarePath, exportPath)only writes files.OverwritePlcProgram(softwarePath, importPath, regexName, keepOnError, dryRun)changes the project and needs--allow-write. Blocks and types of the same name in the open project are replaced by the file content. The tool description tells the agent so.- Prefer
ImportPlcProgramChangesfor edited files; useOverwritePlcProgramonly to replace the whole tree (first import, restore, a folder without git). The name and the description of the whole-tree tool say so, so an agent does not pick it for a vague "import" request. - Both tools preview by default:
dryRunistrue, nothing is imported, andPlannedlists every object withcreateoroverwrite(the action is derived from the file name). The tool descriptions and prompts tell the agent to show that list to you. - A real run (
dryRun=false) is confirmed by you, through the server: it shows a confirmation dialog in the client (MCP elicitation) listing what would be imported and how many objects are overwritten, and imports only when you type "yes, import". The agent cannot answer it for you, and declining or cancelling imports nothing. A client without elicitation support is refused with a message saying so; it can still run the preview. - Saving is not guarded by the server: the agent is told to call
SaveProject(SaveSessionin a local session) only after you say "save project", which depends on the agent following that instruction. Clients can still prompt before every call, because the tools carrydestructiveHint. - Import puts each file into the group its folder implies; the group must already exist. An
.xmlfile counts only below theProgram blocksfolder. ImportPlcProgramChanges(softwarePath, exportPath, regexName, keepOnError, dryRun)takes only the files git reports as changed since the last commit below<exportPath>/<softwarePath>/: modified, staged and new files. Deleted files cannot be imported and are listed inDeleted; files with an open merge conflict go toIgnored. It needs git onPATHand an export folder inside a git repository, and takes the--export-pathand--software-pathpresets. Suggested flow:ExportPlcProgram, commit the export as baseline, edit files,ImportPlcProgramChanges(preview), confirm, run it again withdryRun=false,SaveProject, commit.- Objects may need each other across the two formats (a LAD block calling an SCL block, an instance data block of
a LAD function block). Import therefore works in rounds: it retries what failed as long as the last round
imported something. The response reports
Rounds, and what never succeeded inFailureswith its last error. - The narrower tools stay:
ExportSources/ImportSources(sources only) andExportXmlBlocks/ImportXmlBlock(XML only). softwarePathandexportPathtake the presets from--software-pathand--export-pathlike every other export.
Example prompts using natural language with preset parameters in json config file.
{
"servers": {
"tia-mcp-server": {
"type": "stdio",
"command": "E:\\Labor\\GitHub\\tiaportal-mcp\\src\\TiaMcpServer\\bin\\Debug\\net48\\TiaMcpServer.exe",
"args": [
"--tia-major-version", "21",
"--project-path", "<path-to-project>\\<project-name>.(ap21|als21)",
"--software-path", "<software-path>",
"--export-path", "${workspaceFolder}\\export",
"--preserve-path",
"--allow-write"
],
"env": {}
}
}
}Prompts:
- 'open tia project'
- 'export all types to sources'
- 'export all blocks as sources'
- 'export blocks as sources, which match regex name pattern ".+HMI_.+"'
- 'export all tags'
- 'import modified type sources'
- 'get project tree and save output to project-tree.txt'
- 'get software tree and save output to software-tree.txt'
- 'export watch tables'
- 'export force tables'
- 'export opc ua'
- 'save project'
- 'compile project'
- 'close project'
- 'show doctor diagnostics for tia'
Every tool has a prompt of the same name that you can start as a slash command, for example
/mcp__tia-mcp-server__OpenProject D:\Siemens\Test\TestProject1_V21.ap21. The part after mcp__ is
the server name from your MCP configuration. Claude Code shows the prompt description and the
argument names, matches the typed values to the arguments by position and requires every argument
without a default. A prompt only sends text to the model, which then calls the tool.
A value with spaces goes in double quotes, for example a PC based PLC software or an export folder:
/mcp__tia-mcp-server__ExportXmlBlocks "PC-System_1/Software PLC_1" "D:\My Export"
Claude Code itself splits the text at every space and drops the words beyond the last argument. The
server joins the pieces of a quoted value again, so the value reaches the tool unchanged; ""
passes an empty value. All typed words together must not exceed the number of arguments of the
prompt, so a prompt with few arguments (for example GetSoftwareInfo, which only has
softwarePath) cannot take a value of several words: write a normal request instead of the slash
command.
- .net Framework 4.8 installed
- Siemens TIA Portal V21 installed and running on your machine
- Check if under
Environment Variables/User variable for user <name>the variableTiaPortalLocationis set toC:\Program Files\Siemens\Automation\Portal V21 - User must be in Windows User Group
Siemens TIA Openness
Run the server with --doctor to check all of the above without starting the MCP server:
> TiaMcpServer.exe --doctor
Diagnose:
├─ Connected = False
├─ Project: No project open
├─ Active Version: V21
├─ Installed TIA Portal versions:
│ └─ V21: C:\Program Files\Siemens\Automation\Portal V21
│ ├─ Engineering: OK
│ └─ Portal: OK
├─ User in 'Siemens TIA Openness' user group: True
└─ Write mode (--allow-write): disabled, read-only tools only
The same report is available to MCP clients through the Doctor tool, which additionally returns
the findings as structured content. Both are read-only: they never connect to TIA Portal, open a
project, or change user group membership.
- V21 is the default version.
- Previous versions are also supported, but must use the
--tia-major-versionargument to specify the version. - Export as documents (.s7dcl/.s7res) via
ExportAsDocuments/ExportBlocksAsDocumentsrequires TIA Portal V20 or newer. - Import from documents (.s7dcl/.s7res) via
ImportFromDocuments/ImportBlocksFromDocumentsalso requires TIA Portal V20 or newer. - The same for PLC data types -
ExportTypeAsDocuments,ExportTypesAsDocuments,ImportTypeFromDocuments,ImportTypesFromDocuments- requires TIA Portal V21 or newer: Openness only addedPlcType.ExportAsDocumentsandPlcTypeComposition.ImportFromDocumentsin V21.
A source document is the readable, git-diffable form of an object: <Name>.s7dcl holds the
declaration and body as SCL/LAD/STL text, the optional <Name>.s7res holds comments and
language resources. Every other export in this server writes SimaticML XML instead, which
diffs poorly.
The file names come from TIA Portal, not from this server: an export response lists the files that were actually written, and a batch import discovers a document set by base name rather than assuming one extension. Tag tables and watch tables have no document API in Openness V21 and remain XML-only.
With preservePath the export mirrors the project tree below the system folder - Program blocks for blocks, PLC data types for types - using the folder name as TIA Portal reports it
in the current interface language. ImportTypeFromDocuments and ImportTypesFromDocuments
accept that folder name back as a leading segment of groupPath, so an export can be fed
straight back in.
A PLC data type name is unique across the whole PLC, not just within its group. Importing a
name that already exists into a different group therefore fails with "an object with the name
... already exists in the plc", even with importOption: Override; point groupPath at the
group the type already lives in to replace it.
- As of 2025-09-02: Importing Ladder (LAD) blocks from SIMATIC SD documents requires the companion
.s7resfile to contain en-US tags for all items; otherwise import may fail. This is a known limitation/bug in TIA Portal Openness. ExportXmlBlockrequires a fully qualifiedblockPathlikeGroup/Subgroup/Name. If only a name is provided, the tool fails with an error result that may include suggestions for likely full paths.
These are not gaps in this server - the underlying API offers no operation for them.
- No move or copy for blocks and types.
CopyBlock,MoveBlock,CopyTypeandMoveTypeare composed from export, import and (for a move) deleting the source once the import succeeds. Two consequences are visible: the object must be consistent, because TIA Portal refuses to export an inconsistent one, and its block number travels with it, so importing into the same PLC can hit a number collision. Renaming during a copy is not offered - it would mean rewriting the exported XML. - No generic "create block". Only
CreateFBandCreateInstanceDBexist; every other kind of block has to arrive throughImportXmlBlock. - Read-only objects. System constants cannot be created or changed, the force table cannot
be created or deleted (the system owns one per PLC), the default tag table cannot be deleted,
and the system groups (
Program blocks,PLC data types,PLC tags, ...) cannot be renamed or deleted. These all fail with aNotSupportedmessage rather than an opaque Openness error. - No cross references for watch tables, force tables or external sources;
GetCrossReferencesreportsNotSupportedfor them. - Watch table entries cannot be created or deleted through this server yet. The Openness composition holding them exposes only a comment-row creator, so adding a real entry needs an untyped creation call whose required attribute names must first be read from the live API.
- Safety programs. F-blocks and safety tags reject most edits, sometimes requiring the safety password. The server does not pre-guess Siemens' rules: the underlying error is passed through with its original message.
- Know-how protected blocks and types are rejected before any edit, with a message asking you to remove the protection in TIA Portal first.
- See
tests/TiaMcpServer.Test/README.mdfor environment prerequisites and test asset setup. - Standard command:
dotnet test(run from the repo root). - Test execution policy: offer to run tests, but only execute after explicit user confirmation. Details in
AGENTS.md.
- See
agents.mdfor guidance on working with agentic assistants and the test execution policy (offer to run tests only with explicit user confirmation).
- The Portal layer throws
PortalExceptionwith a short message andPortalErrorCode(NotFound,InvalidParams,InvalidState,ExportFailed,ImportFailed,CreateFailed,DeleteFailed,RenameFailed,NotSupported,WriteDisabled), and attachessoftwarePath,blockPath,exportPathinException.Datawhile preservingInnerExceptionon export failures. - The MCP layer rethrows these as
McpException. Since SDK 2.x, anMcpExceptionthrown from a tool is returned to the client as aCallToolResultwithisError: trueand the message as text content, rather than as a JSON-RPC error, so the model can read the reason and self-correct. ForExportFailedthe message includes a concise reason from the underlying error; forNotFoundit may suggest likely full block paths if a bare name was provided. - Consistency required: TIA Portal never exports inconsistent blocks/types. Single export returns
InvalidParamswith a message to compile first. Bulk export skips inconsistent items and returns them in anInconsistentlist alongsideItems. - Standardization: Exception context metadata is attached in a single catch per portal method right before rethrow, not at inline throw sites. See
docs/error-model.md. - Since 0.2.0 this is implemented once, in the
Operation.Runhelper, which every portal method added for tags, watch tables, external sources, cross references and the write operations routes through. The older export/import methods still carry their hand-written equivalent of the same block; migrating them is tracked inTODO.md. Operation.Runalso serializes all Openness calls behind a lock. Openness objects are not thread-safe and the MCP SDK may dispatch tool calls concurrently; with write tools enabled an unsynchronized race could corrupt project state rather than merely return stale data.
- Built on the ModelContextProtocol .NET SDK 2.2.0.
- Protocol revisions negotiated during
initialize:2024-11-05,2025-03-26,2025-06-18,2025-11-25(the SDK picks the highest the client also supports). - Every tool advertises a human-readable
titleand behaviour annotations (readOnlyHint,destructiveHint,idempotentHint,openWorldHint). - 27 read tools and all 37 write tools publish an
outputSchemaand returnstructuredContent. - Long-running export/import tools report progress via
notifications/progresswhen the client supplies aprogressToken. - Tool failures are returned as tool results with
isError: true(not JSON-RPC errors), so the model can read the message and retry.
- Supported today:
stdio- Program wires
AddMcpServer().WithStdioServerTransport(). - For stdio, logs must go to stderr to avoid corrupting JSON-RPC.
- Program wires
- Available via SDK:
stream(custom streams)- The SDK exposes
WithStreamServerTransport(Stream input, Stream output)which can be used to host over TCP sockets or other streams. - Not wired in this repo yet.
- The SDK exposes
- HTTP/Streamable HTTP: not implemented yet
ModelContextProtocol2.2.0 ships its Streamable HTTP server transport inModelContextProtocol.AspNetCore, which targets .NET 8+.- This server targets
net48(required by TIA Openness), so Streamable HTTP cannot be hosted from this process. - A separate .NET 8+ proxy process would be required to expose this server over HTTP.
The server runs locally over stdio, so every client starts TiaMcpServer.exe itself. Use the
absolute path of the executable (<path-to> below) and double the backslashes in JSON. All
arguments from Command Line Arguments go into args; the presets
(--project-path, --software-path, --export-path, ...) and --allow-write are optional.
-
Workspace file
.vscode/mcp.json(orMCP: Open User Configurationfor all workspaces). The root key isservers. Example with the VS Code extension TIA-Portal MCP-Server and TIA-Portal V21:{ "servers": { "tia-mcp-server": { "type": "stdio", "command": "c:\\Users\\<user>\\.vscode\\extensions\\jheilingbrunner.vscode-tiaportal-mcp-<version>\\srv\\net48\\TiaMcpServer.exe", "args": [ "--tia-major-version", "21", "--project-path", "D:\\Projects\\Plant\\Plant.ap21", "--software-path", "PLC_1", "--export-path", "${workspaceFolder}\\export", "--preserve-path", "--with-dependencies", "--allow-write" ], "env": {} } } }Then switch Copilot Chat to Agent mode and enable the server's tools in the tools picker.
-
Project scope, file
.mcp.jsonin the repository root (checked in, shared with the team). The root key ismcpServers:{ "mcpServers": { "tia-mcp-server": { "type": "stdio", "command": "<path-to>\\TiaMcpServer.exe", "args": [ "--tia-major-version", "21", "--project-path", "D:\\Projects\\Plant\\Plant.ap21", "--software-path", "PLC_1", "--export-path", "${CLAUDE_PROJECT_DIR}\\export", "--preserve-path", "--with-dependencies", "--allow-write" ], "env": {} } } }${CLAUDE_PROJECT_DIR}is expanded by Claude Code to the project root; use an absolute path if your Claude Code version does not. -
The same from the command line (
--scope userfor all projects,--scope projectwrites.mcp.json,--scope localis the default and private). Everything after--is the command:claude mcp add tia-mcp-server --scope project -- "<path-to>\TiaMcpServer.exe" --tia-major-version 21 --project-path "D:\Projects\Plant\Plant.ap21" --software-path PLC_1 --export-path "D:\Export" --preserve-path --with-dependencies
Check it with
claude mcp listor/mcpinside Claude Code.
-
~/.gemini/settings.json(user) or.gemini/settings.jsonin the project (project scope). The root key ismcpServers:{ "mcpServers": { "tia-mcp-server": { "command": "<path-to>\\TiaMcpServer.exe", "args": [ "--tia-major-version", "21", "--project-path", "D:\\Projects\\Plant\\Plant.ap21", "--software-path", "PLC_1", "--export-path", "D:\\Export", "--preserve-path", "--with-dependencies" ], "env": {}, "timeout": 120000 } } }timeoutis in milliseconds; raise it for long exports or compiles. Check it with/mcpinside Gemini CLI. Do not set"trust": truetogether with--allow-write, because that skips the confirmation prompt for the project-changing tools.
-
Create/Edit to add/remove server to
C:\Users\<user>\AppData\Roaming\Claude\claude_desktop_config.json:{ "mcpServers": { "vscode-tiaportal-mcp": { "command": "<path-to>\\TiaMcpServer.exe", "args": [], "env": {} } } }